Ruby 字符串对象

在 Ruby 中一切皆为对象,字符串当然也不例外,本章中,您需要掌握字符串对象的创建方法,通过常见字符串实例方法的应用来掌握字符串的实例方法。更重要的是,要理解字符串也是一个对象。

1. 什么是字符串对象

Ruby 中的 String 对象持有并操纵一个或多个字节的任意序列,通常表示代表人类语言的字符。——官方定义

一个或多个字节的任意序列可以理解为我们所熟悉的语言文字,例如:“小明“、“123“、“abc“、或者特殊符号等。字符串对象会显示为我们为它赋予的文字。除此之外它可以对自身的文本内容进行截取、部分删除、插入文字等操作,比如我想在 “abcd” 的末尾增加一个 “e“,使这个字符串变成 “abcde”。

那么我们如何创建一个字符串对象呢?

2. 字符串对象创建的方法

创建字符串对象的方法有很多种,最常用的创建方式是使用字符串文字:单引号或双引号之间的字符序列。两种形式之间的区别是 Ruby 在构造文字时对字符串进行的处理量。

2.1 单引号

定义:单引号内存放文字的字符串对象。

除少数情况,单引号中的内容将成为字符串的值。

使用场景:定义简单的字符串(不包含转义符以及表达式插值操作)。

实例:

puts 'Hello Ruby!'
# ---- 输出结果 ----
Hello Ruby! 

当您想要在单引号字符串中使用单引号'时,为了不要让 Ruby 将输入的单引号理解为终止符号,您需要使用反斜杠\

实例:

# 输出带有'的单引号字符串
puts 'What\'s your name?'

# ---- 输出结果 ----
What's your name?  

两个连续的反斜杠\\被单个反斜杠替换。

实例:

# 在单引号字符串中输入两个反斜杠
puts 'escape using "\\"'

# ---- 输出结果 ----
escape using "\"

2.2 双引号

定义:双引号内存放文字的字符串对象。

使用场景:推荐用来定义复杂的字符串(包括转义符或者表达式插值操作)。

实例:

# 输出一段文字
puts "Hello Ruby!"

# ---- 输出结果 ----
Hello Ruby!

当使用双引号创建字符串对象时,首先他会查找以反斜杠\开头的字符,进行转义操作,其中最常见转义符为\n,它叫做换行符,当输出包含换行符的字符串的时候,\n会被强制转换为换行。

实例:

# 输出带有换行符的字符串
puts "Goodnight,\nAlice"

# ---- 输出结果 ----
Goodnight,
Alice

其次,双引号字符串做的第二件事是表达式插值,在字符串中,#{表达式}会被表达式的结果替换。

实例:

# 表达式插值
name = 'Alice' #定义一个局部变量name,这里的字符串单引号双引号均可
puts "Goodnight, #{name}"

# ---- 输出结果 ----
Goodnight, Alice

表达式也可以是数学运算。

实例:

x, y, z = 12, 36, 72
puts "x 的值为 #{ x }"
puts "x + y 的值为 #{ x + y }"
puts "x + y + z 的平均值为 #{ (x + y + z)/3 }"

# ---- 输出结果 ----
x 的值为 12
x + y 的值为 48
x + y + z 的平均值为 40

如果表达式只是全局变量$类变量@@实例变量@,则可以省略花括号。变量类型将在之后章节给大家普及。

实例:

puts "This is line #$."

# ---- 输出结果 ----
This is line 1

经验:除了#{}这种表达式插值的形式,使用+也可以进行字符串拼接操作,但是要求进行拼接的两个变量的类型一定是字符串,否则会抛出异常,Ruby 会将#{}表达式中的结果强制转化为字符串,我们不需要关心变量的类型,只需要关心拼接的操作。所以,最好不使用+来拼接字符串。

对比下面两种情况:

x = 12
puts "x 的值为 #{x}"

# ---- 输出结果 ----
x 的值为 12
x = 12
puts "x 的值为 " + x

# ---- 输出结果 ----
Traceback (most recent call last):
	1: from ruby.rb:2:in `<main>'
ruby.rb:2:in `+': no implicit conversion of Integer into String (TypeError)

而这样就不会抛出异常:

x = 12
puts "x 的值为 " + x.to_s # 将12从数字转化成字符串

# ---- 输出结果 ----
x 的值为 12

2.3 %q和%Q

定义:%q同单引号规则,%Q同双引号规则。

使用场景:定义多行字符串。

qQ之后的字符是分隔符,如果是[{(!<则将读取字符串,直到找到匹配的结束符号,否则将一直读取字符直到下一次出现相同的分隔符为止。

实例:

%q/生成单引号字符/	 # 相当于 '生成单引号字符'
%Q!生成双引号字符!	 # 相当于 "生成双引号字符"
%Q{Seconds/day: #{24*60*60}} #相当于 "Seconds/day: #{24*60*60}"

# ---- 输出结果 ----
生成单引号字符
生成双引号字符
Seconds/day: 86400

2.4 Heredoc

定义:Heredoc 是定义多行字符串,同时保持原始缩进和格式的一种方法。

使用场景:这用于嵌入诸如 SQL 或 HTML 之类的代码片段。

实例:

query = <<-SQL
SELECT * FROM food
WHERE healthy = true
SQL

# ---- 输出结果 ----
"SELECT * FROM food\nWHERE healthy = true\n"

解释

您以符号<<-开头,然后是代表此 Heredoc 名称的单词,然后是 Heredoc 内容,然后在此文档的最后用该单词关闭 Heredoc。

3. 字符串实例方法应用

String 可能是最大的内置 Ruby 类,具有超过 75 种标准方法。我将在下面主要介绍最常用的实例方法。String类实例方法官方链接。

3.1 获取字符串长度

用来获取字符串中字符的个数。

实例:

"ruby".length
# 或者
"ruby".size

# ---- 输出结果 ----
4

3.2 检查一个字符串是否为空

Tips:我们将空字符串定义为长度为零的字符串。

实例:

"".empty? 
# 相当于 
"".size == 0 # 但是empty?是更好的选择

# ---- 输出结果 ----
true

3.3 如何提取一个子字符串

子字符串(substring)是字符串的一小部分,如果您只想要该特定部分的字符串(例如开头,中间或结尾),则很有用。

一种方法是使用方括号内的起始索引和多个字符,以逗号分隔:

实例:

string = "abc123" # 索引以0开始,代表第一个字符
# 从索引0开始截取3个字符
string[0,3]
# 从索引3开始截取3个字符
string[3,3]

# ---- 输出结果 ----
"abc"
"123"

解释:

  1. 第一个数字是起始索引;

  2. 第二个数字是您想要多少个字符。

您还可以使用范围range):

实例:

# 提取从第一个字符开始直到倒数第二个字符之间的字符串
string = "abc123"
string[0..-2]

# ---- 输出结果 ----
"abc12"

解释:

  1. 第一个数字仍然是起始索引,但是第二个索引是结束索引(含端点);

  2. -2代表倒数第二个字符,而-1是最后一个字符。

如果您想要删除或替换子字符串,您可以这样做:

实例:

# 将从第一个字符开始直到第三个字符的字符串设置成空字符串
string = "abc123"
string[0..2] = ""
string

# ---- 输出结果 ----
"123"

3.4 如何找出一个字符串是否包含另一个字符串

include? 方法:

Tips:在Ruby中,我们约定后面有一个?的方法返回值一定是true或者false

实例:

# "Today is Saturday"里面是否包含"Saturday"
string = "Today is Saturday"
string.include?("Saturday")

# ---- 输出结果 ----
true

解释:结果会返回true或者false

index方法:

实例:

string = "Today is Sunday"
string.index("day")

# ---- 输出结果 ----
2

解释:此方法会返回查询的字符串的第一个字符在被查询字符串中的索引。

Tips:如果结果是不包含,会返回nil

3.5 判断两个字符串是否相同(不区分大小写)

Ruby 字符串比较是要区分大小写的,如果比较的两个字符串大小不同,则不相等。

对此我们常用的方法是使方程式的两边的字符串都小写大写

实例:

# 将两组字符串都转成大写或者小写
lang1 = "ruby"
lang2 = "Ruby"
puts lang1.upcase == lang2.upcase
puts lang1.downcase == lang2.downcase

# ---- 输出结果 ----
true
true

Tips : casecmp?方法也可以做到这种事,使用较少,不推荐使用

3.6 如何删除字符串两侧多余的空格

您可以使用strip方法删除多余的空格:

实例:

# 删除两侧多余的空格
extra_space = "   Hello World "
extra_space.strip

# ---- 输出结果 ----
"Hello World"

经验:当提交表单中包含姓名、邮箱、手机号这些参数的时候,经常会用到这个方法。

当您只想除去左侧或者右侧的多余空格时,您可以使用lstriprstrip

实例:

extra_space = "   Hello World "
p extra_space.lstrip # 删除左侧多余的空格
p extra_space.rstrip # 删除右侧多余的空格

# ---- 输出结果 ----
"Hello World "
"   Hello World"

3.7 字符串的前缀与后缀

查看字符串是否以特定前缀开头:

实例:

string = "ruby programming"
string.start_with? "ruby"

# ---- 输出结果 ----
true

查看字符串是否以特定后缀结尾:

实例:

string = "ruby programming"
string.end_with? "programming"

# ---- 输出结果 ----
true

删除指定前缀:

实例:

string = "ruby programming"
string.delete_prefix "ruby "

# ---- 输出结果 ----
"programming"

删除指定后缀:

实例:

string = "ruby programming"
string.delete_suffix " programming"

# ---- 输出结果 ----
"ruby"

Tips : delete_prefixdelete_suffix要在Ruby2.5以上的版本才可以使用

3.8 将字符串转换为字符数组

使用split方法可以很容易地将字符串分割成字符数组:

实例:

string = "a b c d"
string.split

# ---- 输出结果 ----
["a", "b", "c", "d"]

默认情况下,split将使用空格作为分隔符,但是您可以将参数传递给此方法以指定其他分隔符。

实例:

# 将逗号作为分隔符
string = "a,b,c,d"
string.split(",")

# ---- 输出结果 ----
["a", "b", "c", "d"]

3.9 将数组转换为字符串

如果您想获取一个字符串数组并将这些字符串连接成一个大字符串,则可以使用join方法。

实例:

# 将由'a', 'b', 'c'字符组成的数组合并成一个字符串
arr = ['a', 'b', 'c']
arr.join

# ---- 输出结果 ----
"abc"

也可以通多传递参数指定字符分隔符。

实例:

arr = ['a', 'b', 'c']
arr.join("-")

# ---- 输出结果 ----
"a-b-c"

3.10 将字符串转换为整数

如果要将"49"之类的字符串转换为整数(Integer)的49,可以使用to_i方法。

实例:

"49".to_i

# ---- 输出结果 ----
49

注意事项:如果您使用不包含数字的字符串尝试此操作,则将获得0。

实例:

"a".to_i

# ---- 输出结果 ----
0

3.11 检查字符串内容是否为一个整数

使用正则表达式(regular expression)来进行判断:

实例:

"123".match?(/\A-?\d+\Z/)
"123bb".match?(/\A-?\d+\Z/)

# ---- 输出结果 ----
true
false

Tips : match?是从ruby2.4以后才引入的,2.4之前的版本可以使用match来代替。

解释:上述正则表达式的意思为从字符串的开头(\A)检查是否有一个可选的负号(-??代表可选),然后确保中间有一些数字(\d+)直到字符串结尾(\Z)没有其它字符。

3.12 如何附加字符

您可以通过将字符附加到现有字符串来从较小的字符串构建较大的字符串。这也称为字符串的串联(string concatenation

我们通过<<方法来实现这个操作

实例:

string = ""
string << "hello"
string << " "
string << "there"

# ---- 输出结果 ----
"hello there"

Tips:不要使用+=来进行字符串连接,因为每次都会创建一个新字符串,这对性能不利!

3.13 遍历字符串的字符

有时您需要对字符串的每个字符进行操作,这个时候就需要遍历字符串的每个字符。

第一种方法,您可以使用each_char方法:

实例:

# 输出每一个字符
"rubyguides".each_char { |ch| puts ch  # 这里ch参数的名称可以是任意的}

# ---- 输出结果 ----
r
u
b
y
g
u
i
d
e
s

另外,您也可以使用chars方法将字符串转换为字符数组,对数组上每个对象进行迭代(iterate)。

实例:

array_of_characters = "rubyguides".chars

# ---- 输出结果 ----
["r", "u", "b", "y", "g", "u", "i", "d", "e", "s"]

3.14 字符串转换为大写或小写

如果要将字符串所有字符全部大写,可以使用upcase方法:

实例:

"abcd".upcase

# ---- 输出结果 ----
"ABCD"

如果要将字符串所有字符全部小写,可以使用downcase方法。

实例:

"ABCD".downcase

# ---- 输出结果 ----
"abcd"

3.15 创建多行字符串

第一种方法,使用 Heredoc:

实例:

b = <<-STRING
aaa
bbb
ccc
STRING

# ---- 输出结果 ----
"aaa\nbbb\nccc\n"

另一种,使用%Q

实例:

a = %Q(aaa
bbb
ccc
)

# ---- 输出结果 ----
"aaa\nbbb\nccc\n"

3.16 使用gsub替换字符串中的文本

如果要替换字符串中的文本,请使用gsub方法:

实例:

# 让我们用“cats”代替“dogs”一词
string = "We have many dogs"
string.gsub("dogs", "cats")

# ---- 输出结果 ----
"We have many cats"

如果要删除字符串,请使用空字符串作为第二个参数。

实例:

string = "abccc"
string.gsub("c", "")

# ---- 输出结果 ----
"ab"

注意事项:

  1. gsub方法返回一个新字符串;

  2. 如果要将更改应用于原始字符串,可以使用gsub!方法。

gsub方法还可以将正则表达式作为参数,因此您可以根据模式替换而不是确切的单词。

实例:

string = "We have 3 cats"
string.gsub(/\d+/, "5")

# ---- 输出结果 ----
"We have 5 cats"

解释:这会将字符串中的所有数字(\d+)替换为数字5。

我们也可以和块(block)一同使用

title = "the lord of the rings"
title.gsub(/\w+/) { |word| word.capitalize }

# ---- 输出结果 ----
"The Lord Of The Rings"

Tips : 那么gsub vs sub有什么区别呢?

subgsub使用方法一样,但是sub只会替换第一个匹配项,gsub会替换所有项。

3.17 从字符串中删除最后的\n\r

如果您要求用户输入某些内容(使用Kernel#gets方法),则在字符串末尾会有换行符(\n),这将妨碍您直接比较字符串。

删除多余的换行符(\n)的最佳方法是使用chomp方法。

实例:

puts "What's your name?"
name = gets
# 输入名字Alice

# ---- 输出结果 ----
"Alice\n"

使用chomp方法后:

puts "What's your name?"
name = gets.chomp
# 输入名字Alice

# ---- 输出结果 ----
"Alice"

Tipschopchomp的区别

chomp只会删除字符串末尾的\n或者\r

chop会删除字符串末尾最后一个字符,不管是什么字符。

从 Ruby 2.3 开始,chomp 方法采用一个可选参数,该参数允许您删除要删除的字符。

实例:

"abcd?".chomp("?")

# ---- 输出结果 ----
"abcd"

如果传入参数的字符不存在,它将返回原始字符串。

3.18 如何更改字符串编码

字符串按字节序列存储,根据它们的编码,它们变成可以看到的字符。

例如,ASCII 编码中的数字 65 表示字母“ A”。

但是,还有更复杂的编码,例如 UTF-8,它允许您表示来自不同语言(中文等)甚至表情符号的字符。

要获取字符串的当前编码,可以使用encoding方法。

实例:

"abc".encoding

# ---- 输出结果 ----
Encoding:UTF-8

从磁盘读取文件或从网站下载某些数据时,可能会遇到编码问题。

您通常可以通过转换编码的方法force_encoding来解决该问题。

实例:

"abc".force_encoding("UTF-8")

3.19 字符计数

您可以使用count方法计算某一个字符在字符串中出现的次数。

实例:

str = "aaab"
str.count("a")

# ---- 输出结果 ----
3

str.count("b")

# ---- 输出结果 ----
1

4. 小结

在本章中,您知道了什么字符串,了解如何创建一个字符串对象,学习了字符串常见的实例方法以及具体一些应用。

打好字符串的基础后,接下来让我们继续来学习下一章吧。