Ruby 字符串

字符串是编程里用得最多的数据类型。Ruby 的字符串功能非常丰富——单/双引号有明确分工、插值语法优雅、还有 heredoc、frozen 等特性。本章把字符串的常用操作过一遍,看完就能应付 90% 的日常需求。

1. 单引号 vs 双引号

这是 Ruby 字符串最基础也最常被忽略的区别。单引号几乎不解释,双引号会解释转义和插值:

# 单引号:几乎不解释,看到什么是什么
puts 'hello\nworld'      # 字面输出 hello\nworld(反斜杠不转义)
puts 'It\'s me'           # 唯一转义:用 \' 表示单引号本身

# 双引号:会解释转义序列与插值
puts "hello\nworld"      # 真的换行输出
puts "tab\there"         # 真的有制表符
puts "code: #{65}"        # 输出 code: 65(支持任意表达式)

# 性能:单引号略快(不需要解析插值),不需要插值时优先用单引号

记住这条:不需要插值就用单引号,需要插值或转义才用双引号。这是 Ruby 社区的性能与可读性约定。

2. 字符串插值(Ruby 最优雅特性之一)

双引号字符串里把表达式包进花括号(前面加井号)就能嵌入任意 Ruby 代码,远比其他语言的 + 拼接或 printf 优雅:

# 字符串插值:把任意 Ruby 表达式嵌入字符串
name = "Ruby"
puts "Hello, #{name}!"           # Hello, Ruby!

# 插值里可以是任意表达式
puts "1 + 2 = #{1 + 2}"          # 1 + 2 = 3
puts "现在时间: #{Time.now}"
puts "长度: #{name.length}"

# 调用方法
user = "alice"
puts "大写: #{user.upcase}"      # 大写: ALICE

# 嵌套插值也行(但别滥用)
puts "Hi, #{"#{"nested"}"}"      # Hi, nested

3. heredoc:多行字符串

写 SQL、HTML 模板、长文本时,heredoc 是救星。Ruby 的 heredoc 有几种变体,常用的是 <<-(吃掉结尾缩进)和 <<~(自动去掉公共缩进,Ruby 2.3+):

# heredoc:多行字符串,常用于写 SQL、HTML 模板
sql = <<-SQL
  SELECT * FROM users
  WHERE age > 18
  ORDER BY name
SQL

puts sql
# 输出三行原文,缩进被 <<- 的减号吃掉

# 普通版 <<~(波浪号,Ruby 2.3+):自动去掉公共缩进
text = <<~TEXT
  第一行
    第二行(缩进保留相对关系)
  第三行
TEXT

4. 常用方法(第一组:查找与替换)

Ruby 字符串方法多到记不完,下面是实战最常用的几组。先看长度、空白、大小写、查找替换:

s = "  Hello, Ruby!  "

# 长度与空判断
s.length          # 17
s.size            # 17(别名)
s.empty?          # false
"".empty?         # true

# 去空白
s.strip           # "Hello, Ruby!"(两端去空白)
s.lstrip          # 只去左
s.rstrip          # 只去右

# 大小写
"abc".upcase      # "ABC"
"ABC".downcase    # "abc"
"hello".capitalize  # "Hello"
"hello world".titleize  # Rails 才有

# 查找与判断
s.include?("Ruby")    # true
s.start_with?("  H")  # true
s.end_with?("!")

# 替换
"hello".sub("l", "L")     # "heLlo"(只替换第一个)
"hello".gsub("l", "L")    # "heLLo"(全部)
"hello".gsub(/l+/, "L")   # "heLo"(支持正则)

一个高频面试题:subgsub 的区别——前者只替换第一个,后者替换所有。gsub 还支持正则,是做文本处理的利器。

5. 常用方法(第二组:分割、拼接、转换)

# 分割与拼接
"1,2,3,4".split(",")        # ["1", "2", "3", "4"]
"a-b-c".split("-")          # ["a", "b", "c"]

%w[a b c].join(",")         # "a,b,c"
[1, 2, 3].join("-")         # "1-2-3"

# 字符数组
"hello".chars               # ["h", "e", "l", "l", "o"]
"hello".bytes               # [104, 101, 108, 108, 111]

# 反转、重复
"hello".reverse             # "olleh"
"ab" * 3                    # "ababab"(乘法重复)

# 与数字互转
"42".to_i                   # 42
"3.14".to_f                 # 3.14
"42abc".to_i                # 42(前缀解析)
"abc".to_i                  # 0(解析失败给 0)
42.to_s                     # "42"

注意 split 返回数组,join 把数组拼回字符串,二者互为逆操作。字符串乘法 "ab" * 3 这种"语法糖"在 Ruby 里很常见,读起来像自然语言。

6. frozen string literal

Ruby 字符串默认可变,但每次修改都会创建新对象,影响性能。从 Ruby 2.3 开始,可以在文件首行加魔法注释,让该文件所有字符串字面量变成 frozen(不可变):

# frozen_string_literal:让字符串不可变
# 在文件第一行写魔法注释
# frozen_string_literal: true

# 之后该文件里所有字符串字面量都变成 frozen
s = "hello"
s << " world"      # FrozenError: can't modify frozen String

# 单个字符串用 -e 后缀也能 frozen
s = "hello"frozen  # 这种写法很少用

# 为什么要有这个?性能!
# Ruby 3.0 开始默认倾向 frozen,避免每次创建新对象

这是社区为了提升性能引入的特性。新项目里都建议开启,Rails 7+ 默认开启。修改字符串时改用 +=... 不可变方式。

7. 格式化与字面量语法

# 格式化:% 格式符(类似 C 的 sprintf)
puts "%s 有 %d 岁" % ["Alice", 30]   # Alice 有 30 岁
puts "%.2f" % 3.14159                 # 3.14

# sprintf 与 format 方法
sprintf("%05d", 42)    # "00042"
format("%-10s|%10s", "name", "age")   # 左右对齐

# %w 数组字面量:用空白分隔生成字符串数组
%w[apple banana cherry]    # ["apple", "banana", "cherry"]
%w(apple banana)           # 同上,分隔符可换

# %i 符号数组
%i[apple banana]           # [:apple, :banana]

%w实战超高频——写数组配置时省去一堆引号逗号。%i 是它的符号版。

小结

本章覆盖了字符串的日常操作。最该记住:单/双引号的区别、字符串插值语法、gsub 配正则、%w 字面量。下一篇看 Ruby 数组,把另一个核心集合类型讲透。

← 上一篇 Ruby 块与 yield

下一篇 Ruby 数组

✈️💬