Skip to content

Ruby 字符串(String)

字符串是编程中最常用的数据类型之一,用于存储和操作文本数据。Ruby中的字符串功能强大且灵活,提供了丰富的内置方法来处理文本。本章将详细介绍Ruby中字符串的创建、操作和处理方法。

🎯 字符串基础

字符串定义

Ruby支持多种方式定义字符串,每种方式都有其特定的用途:

ruby
# 单引号字符串(不解析转义字符和插值)
name = '张三'
message = 'Hello\nWorld'  # \n不会被解析为换行符
puts message  # 输出: Hello\nWorld

# 双引号字符串(解析转义字符和插值)
name = "李四"
age = 25
message = "你好, #{name}! 你今年#{age}岁了。"
greeting = "Hello\nWorld"  # \n会被解析为换行符
puts greeting
# 输出:
# Hello
# World

# 多行字符串(heredoc语法)
poem = <<~TEXT
  静夜思
  床前明月光,
  疑是地上霜。
  举头望明月,
  低头思故乡。
TEXT

puts poem
# 输出:
# 静夜思
# 床前明月光,
# 疑是地上霜。
# 举头望明月,
# 低头思故乡。

# 使用%q和%Q定义字符串
single_quoted = %q(这是一个'单引号'字符串)
double_quoted = %Q(这是一个"双引号"字符串,包含#{name})

puts single_quoted  # 这是一个'单引号'字符串
puts double_quoted  # 这是一个"双引号"字符串,包含李四

字符串编码

Ruby 1.9之后支持多种字符编码:

ruby
# 查看字符串编码
str = "你好"
puts str.encoding  # UTF-8

# 指定编码
str_with_encoding = "Hello".force_encoding("ASCII")
puts str_with_encoding.encoding  # ASCII

# 转换编码
utf8_str = "你好".encode("UTF-8")
puts utf8_str

🔤 字符串操作

字符串连接

ruby
# 使用+连接
first_name = "张"
last_name = "三"
full_name = first_name + last_name
puts full_name  # 张三

# 使用<<连接(修改原字符串)
greeting = "你好, "
greeting << "世界!"
puts greeting  # 你好, 世界!

# 使用concat方法
message = "Hello".concat(" ", "World")
puts message  # Hello World

# 使用插值(推荐)
name = "Ruby"
version = "3.0"
info = "#{name} #{version}"
puts info  # Ruby 3.0

字符串重复和长度

ruby
# 重复字符串
line = "-" * 20
puts line  # --------------------

# 获取字符串长度
str = "Hello, 世界!"
puts str.length    # 10
puts str.size      # 10
puts str.bytesize  # 13 (字节长度)

# 检查是否为空
empty_str = ""
puts empty_str.empty?  # true
puts " ".empty?        # false
puts " ".strip.empty?  # true

字符串比较

ruby
# 基本比较
puts "hello" == "hello"  # true
puts "hello" == "Hello"  # false (区分大小写)

# 忽略大小写比较
puts "hello".casecmp("Hello")  # 0 (相等)
puts "a".casecmp("B")          # -1 (小于)
puts "c".casecmp("B")          # 1 (大于)

# 包含关系
puts "Hello, World!".include?("World")  # true
puts "Hello, World!".start_with?("Hello")  # true
puts "Hello, World!".end_with?("World!")   # true

🔍 字符串查找和替换

查找子字符串

ruby
text = "Hello, Ruby World! Welcome to Ruby programming."

# 查找位置
puts text.index("Ruby")      # 7
puts text.rindex("Ruby")     # 31 (从右边查找)
puts text.index("Python")    # nil (未找到)

# 使用正则表达式查找
puts text.index(/R\w+/)      # 7 (匹配以R开头的单词)

# 获取字符
puts text[0]          # H
puts text[7]          # R
puts text[-1]         # .
puts text[7, 4]       # Ruby
puts text[7..10]      # Ruby

替换子字符串

ruby
text = "Hello, Ruby World! Welcome to Ruby programming."

# 替换第一个匹配项
new_text = text.sub("Ruby", "Python")
puts new_text  # Hello, Python World! Welcome to Ruby programming.

# 替换所有匹配项
new_text = text.gsub("Ruby", "Python")
puts new_text  # Hello, Python World! Welcome to Python programming.

# 使用正则表达式替换
new_text = text.gsub(/R\w+/, "Python")
puts new_text  # Hello, Python World! Welcome to Python programming.

# 使用块进行复杂替换
new_text = text.gsub(/\b\w+\b/) { |word| word.upcase }
puts new_text  # HELLO, RUBY WORLD! WELCOME TO RUBY PROGRAMMING.

🔄 字符串变换

大小写转换

ruby
text = "Hello, World!"

# 大小写转换
puts text.upcase      # HELLO, WORLD!
puts text.downcase    # hello, world!
puts text.capitalize  # Hello, world!
puts text.swapcase    # hELLO, wORLD!

# 首字母大写
title = "hello world"
puts title.capitalize  # Hello world

# 每个单词首字母大写
sentence = "hello world ruby programming"
puts sentence.split.map(&:capitalize).join(" ")  # Hello World Ruby Programming

去除空白字符

ruby
text = "  Hello, World!  "

# 去除两边空白
puts text.strip      # Hello, World!
puts text.lstrip     # Hello, World!  
puts text.rstrip     #   Hello, World!

# 去除所有空白
compact_text = "  Hello   World  !  "
puts compact_text.gsub(/\s+/, " ").strip  # Hello World !

分割和连接

ruby
# 分割字符串
sentence = "apple,banana,orange,grape"
fruits = sentence.split(",")
puts fruits.inspect  # ["apple", "banana", "orange", "grape"]

# 使用正则表达式分割
text = "apple  banana\torange\ngrape"
words = text.split(/\s+/)
puts words.inspect  # ["apple", "banana", "orange", "grape"]

# 连接数组为字符串
puts fruits.join(", ")  # apple, banana, orange, grape
puts fruits.join(" | ") # apple | banana | orange | grape

🧮 字符串格式化

sprintf和格式化

ruby
name = "张三"
age = 25
score = 95.5

# 使用sprintf格式化
formatted = sprintf("姓名: %s, 年龄: %d, 分数: %.1f", name, age, score)
puts formatted  # 姓名: 张三, 年龄: 25, 分数: 95.5

# 使用%操作符
formatted = "姓名: %s, 年龄: %d, 分数: %.1f" % [name, age, score]
puts formatted  # 姓名: 张三, 年龄: 25, 分数: 95.5

# 数字格式化
puts "%04d" % 42        # 0042 (补零)
puts "%.2f" % 3.14159   # 3.14 (保留两位小数)
puts "%10s" % "Ruby"    # "      Ruby" (右对齐)
puts "%-10s" % "Ruby"   # "Ruby      " (左对齐)

字符串插值

ruby
name = "Ruby"
version = "3.0"
release_date = "2020-12-25"

# 基本插值
info = "#{name} #{version} 发布于 #{release_date}"
puts info  # Ruby 3.0 发布于 2020-12-25

# 表达式插值
x, y = 10, 20
result = "#{x} + #{y} = #{x + y}"
puts result  # 10 + 20 = 30

# 控制插值格式
price = 123.456
formatted_price = "价格: #{"%.2f" % price}"
puts formatted_price  # 价格: 123.46

🔧 字符串实用方法

字符串验证

ruby
# 检查字符串类型
puts "123".numeric?     # true (需要自定义方法)
puts "123".match?(/^\d+$/)  # true (使用正则表达式)

# 自定义验证方法
class String
  def numeric?
    !!Float(self)
  rescue ArgumentError, TypeError
    false
  end
  
  def alphabetic?
    match?(/^[a-zA-Z]+$/)
  end
  
  def alphanumeric?
    match?(/^[a-zA-Z0-9]+$/)
  end
end

puts "123".numeric?        # true
puts "abc".alphabetic?     # true
puts "abc123".alphanumeric? # true

字符串处理实用技巧

ruby
# 安全导航(避免nil错误)
name = nil
puts name&.upcase       # nil (不会抛出错误)
puts name&.length       # nil

# 空值处理
def safe_upcase(str)
  str&.upcase || ""
end

puts safe_upcase("hello")  # HELLO
puts safe_upcase(nil)      # ""

# 字符串截断
def truncate(str, length = 20, omission = "...")
  return str if str.length <= length
  str[0, length - omission.length] + omission
end

long_text = "这是一段非常长的文本,需要被截断处理"
puts truncate(long_text, 15)  # 这是一段非常长的文...

🎯 字符串实践示例

文本处理工具

ruby
class TextProcessor
  def initialize(text)
    @text = text
  end
  
  # 统计单词数量
  def word_count
    @text.split(/\s+/).length
  end
  
  # 统计字符数量(不含空格)
  def char_count(exclude_spaces = true)
    if exclude_spaces
      @text.gsub(/\s/, "").length
    else
      @text.length
    end
  end
  
  # 查找最常见的单词
  def most_common_word
    words = @text.downcase.gsub(/[^\w\s]/, "").split(/\s+/)
    word_count = Hash.new(0)
    words.each { |word| word_count[word] += 1 }
    word_count.max_by { |word, count| count }&.first
  end
  
  # 替换敏感词
  def censor_words(bad_words, replacement = "*")
    result = @text
    bad_words.each do |word|
      pattern = Regexp.escape(word)
      result = result.gsub(/#{pattern}/i) do |match|
        replacement * match.length
      end
    end
    result
  end
  
  # 生成摘要
  def summarize(max_words = 10)
    words = @text.split(/\s+/)
    if words.length <= max_words
      @text
    else
      words[0, max_words].join(" ") + "..."
    end
  end
end

# 使用文本处理器
text = "Ruby是一种动态、开源的编程语言,专注于简洁和效率。Ruby的语法优雅,易于阅读和编写。"
processor = TextProcessor.new(text)

puts "单词数量: #{processor.word_count}"  # 单词数量: 26
puts "字符数量: #{processor.char_count}"  # 字符数量: 45
puts "摘要: #{processor.summarize(10)}"
# 摘要: Ruby是一种动态、开源的编程语言,专注于简洁和效率。Ruby的语法优雅,易于阅读和...

# 敏感词过滤示例
content = "这个产品真的很烂,质量太差了!"
bad_words = ["烂", "差"]
filtered = processor.censor_words(bad_words)
puts filtered  # 这个产品真的很**,质量太*了!

字符串验证器

ruby
class StringValidator
  def self.email?(str)
    pattern = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
    str.match?(pattern)
  end
  
  def self.phone?(str)
    pattern = /\A1[3-9]\d{9}\z/
    str.match?(pattern)
  end
  
  def self.url?(str)
    pattern = /\Ahttps?:\/\/[\w\-]+(\.[\w\-]+)+[/#?]?.*\z/
    str.match?(pattern)
  end
  
  def self.strong_password?(str)
    # 至少8位,包含大小写字母、数字和特殊字符
    return false if str.length < 8
    has_upper = str.match?(/[A-Z]/)
    has_lower = str.match?(/[a-z]/)
    has_digit = str.match?(/\d/)
    has_special = str.match?(/[!@#$%^&*(),.?":{}|<>]/)
    
    has_upper && has_lower && has_digit && has_special
  end
  
  def self.chinese_id_card?(str)
    # 简化的身份证验证(18位数字,最后一位可能是X)
    pattern = /\A\d{17}[\dXx]\z/
    str.match?(pattern)
  end
end

# 使用验证器
puts StringValidator.email?("user@example.com")           # true
puts StringValidator.email?("invalid.email")             # false
puts StringValidator.phone?("13812345678")               # true
puts StringValidator.url?("https://www.example.com")     # true
puts StringValidator.strong_password?("Password123!")    # true
puts StringValidator.chinese_id_card?("110101199001011234") # true

字符串格式化工具

ruby
class StringFormatter
  # 驼峰命名转换为蛇形命名
  def self.camel_to_snake(str)
    str.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
       .gsub(/([a-z\d])([A-Z])/, '\1_\2')
       .downcase
  end
  
  # 蛇形命名转换为驼峰命名
  def self.snake_to_camel(str)
    str.split('_').map.with_index { |word, i| 
      i == 0 ? word : word.capitalize 
    }.join
  end
  
  # 格式化电话号码
  def self.format_phone(phone)
    phone.gsub(/\D/, "")  # 移除非数字字符
         .gsub(/(\d{3})(\d{4})(\d{4})/, '\1-\2-\3')
  end
  
  # 格式化金额
  def self.format_currency(amount, currency = "¥")
    "#{currency}#{'%.2f' % amount.to_f}"
  end
  
  # 格式化日期
  def self.format_date(date_str, format = :cn)
    case format
    when :cn
      date_str.gsub(/(\d{4})-(\d{2})-(\d{2})/, '\1年\2月\3日')
    when :us
      date_str.gsub(/(\d{4})-(\d{2})-(\d{2})/, '\2/\3/\1')
    else
      date_str
    end
  end
end

# 使用格式化工具
puts StringFormatter.camel_to_snake("userName")        # user_name
puts StringFormatter.camel_to_snake("XMLHttpRequest")  # xml_http_request
puts StringFormatter.snake_to_camel("user_name")       # userName
puts StringFormatter.format_phone("13812345678")       # 138-1234-5678
puts StringFormatter.format_currency(1234.5)           # ¥1234.50
puts StringFormatter.format_date("2023-12-25", :cn)    # 2023年12月25日

📊 字符串性能优化

字符串构建优化

ruby
# 低效的方式(每次连接都创建新对象)
def inefficient_build(strings)
  result = ""
  strings.each { |str| result += str }
  result
end

# 高效的方式(使用<<修改原对象)
def efficient_build(strings)
  result = ""
  strings.each { |str| result << str }
  result
end

# 最高效的方式(使用数组连接)
def most_efficient_build(strings)
  strings.join("")
end

# 使用StringIO处理大量字符串操作
require 'stringio'

def build_with_stringio(parts)
  io = StringIO.new
  parts.each { |part| io << part }
  io.string
end

字符串冻结

ruby
# 冻结字符串避免修改
CONSTANT_STRING = "这是一个常量字符串".freeze

# 冻结字符串字面量(Ruby 3.0默认)
# frozen_string_literal: true
# str = "这将自动冻结"

# 检查字符串是否冻结
puts CONSTANT_STRING.frozen?  # true

🎯 字符串最佳实践

1. 选择合适的字符串定义方式

ruby
# 对于简单文本,使用双引号(支持插值)
name = "张三"
greeting = "你好, #{name}!"

# 对于包含特殊字符的文本,使用单引号
sql = 'SELECT * FROM users WHERE name = "张三"'

# 对于多行文本,使用heredoc
template = <<~HTML
  <div class="user-card">
    <h1>#{name}</h1>
    <p>欢迎使用我们的服务</p>
  </div>
HTML

2. 安全处理用户输入

ruby
class SafeStringHandler
  # 转义HTML特殊字符
  def self.escape_html(str)
    str.gsub(/&/, "&amp;")
       .gsub(/</, "&lt;")
       .gsub(/>/, "&gt;")
       .gsub(/"/, "&quot;")
       .gsub(/'/, "&#39;")
  end
  
  # 安全的字符串截断
  def self.safe_truncate(str, length, omission = "...")
    return str if str.nil? || str.length <= length
    str[0, length - omission.length] + omission
  end
  
  # 清理字符串(移除控制字符)
  def self.sanitize(str)
    str.gsub(/[[:cntrl:]]/, "")
  end
end

# 使用安全处理
user_input = "<script>alert('XSS')</script>"
safe_output = SafeStringHandler.escape_html(user_input)
puts safe_output  # &lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;

3. 字符串编码处理

ruby
class EncodingHandler
  # 统一转换为UTF-8
  def self.to_utf8(str)
    return str if str.encoding == Encoding::UTF_8
    str.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
  end
  
  # 检测并处理编码
  def self.handle_encoding(str)
    # 检测编码
    detected_encoding = CharlockHolmes::EncodingDetector.detect(str)
    
    if detected_encoding && detected_encoding[:encoding] != 'UTF-8'
      str.force_encoding(detected_encoding[:encoding])
         .encode('UTF-8', invalid: :replace, undef: :replace)
    else
      str
    end
  rescue
    str.force_encoding('UTF-8')
  end
end

📚 下一步学习

掌握了Ruby字符串操作后,建议继续学习:

继续您的Ruby学习之旅吧!

本站内容仅供学习和研究使用。