类 String

一个 String 对象包含任意的字节序列,通常表示文本或二进制数据。可以使用 String::new 或使用字面量来创建 String 对象。

String 对象与 Symbol 对象的不同之处在于,Symbol 对象被设计为用作标识符,而不是文本或数据。

您可以使用以下方式显式创建 String 对象

您可以使用以下方法将某些对象转换为字符串

一些 String 方法会修改 self。通常,名称以 ! 结尾的方法会修改 self 并返回 self;通常,类似命名的方法(不带 !)会返回一个新的字符串。

一般来说,如果一个方法同时存在感叹号版本和非感叹号版本,则感叹号版本会改变原对象,而非感叹号版本不会。但是,没有感叹号的方法也可能会改变原对象,例如 String#replace

替换方法

这些方法执行替换操作

  • String#sub:执行一次替换(或不替换);返回一个新的字符串。

  • String#sub!:执行一次替换(或不替换);如果发生任何更改,则返回 self,否则返回 nil

  • String#gsub:执行零次或多次替换;返回一个新的字符串。

  • String#gsub!:执行零次或多次替换;如果发生任何更改,则返回 self,否则返回 nil

这些方法中的每一个都接受

  • 第一个参数,patternStringRegexp),指定要替换的子字符串。

  • 以下任意一种

    • 第二个参数,replacementStringHash),确定替换字符串。

    • 一个用于确定替换字符串的块。

本节中的示例大多使用 String#subString#gsub 方法;所说明的原则适用于所有四个替换方法。

参数 pattern

参数 pattern 通常是正则表达式

s = 'hello'
s.sub(/[aeiou]/, '*') # => "h*llo"
s.gsub(/[aeiou]/, '*') # => "h*ll*"
s.gsub(/[aeiou]/, '')  # => "hll"
s.sub(/ell/, 'al')     # => "halo"
s.gsub(/xyzzy/, '*')   # => "hello"
'THX1138'.gsub(/\d+/, '00') # => "THX00"

pattern 是字符串时,其所有字符都被视为普通字符(而不是 Regexp 特殊字符)

'THX1138'.gsub('\d+', '00') # => "THX1138"

String replacement

如果 replacement 是一个字符串,则该字符串确定要替换匹配文本的替换字符串。

上面的每个示例都使用一个简单的字符串作为替换字符串。

String replacement 可能包含对模式捕获的反向引用

  • \nn 是一个非负整数)引用 $n

  • \k<name> 引用名为 name 的命名捕获。

有关详细信息,请参阅 Regexp

请注意,在字符串 replacement 中,诸如 $& 之类的字符组合被视为普通文本,而不是特殊的匹配变量。但是,您可以使用以下组合引用一些特殊的匹配变量

  • \&\0 对应于 $&,其中包含完整的匹配文本。

  • \' 对应于 $',其中包含匹配后的字符串。

  • \` 对应于 $`,其中包含匹配前的字符串。

  • \+ 对应于 $+,其中包含最后一个捕获组。

有关详细信息,请参阅 Regexp

请注意,\\ 被解释为转义符,即单个反斜杠。

还要注意,字符串字面量会消耗反斜杠。有关字符串字面量的详细信息,请参阅 字符串字面量

反向引用通常以附加的反斜杠开头。例如,如果您想在带有双引号字符串字面量的 replacement 中编写反向引用 \&,则需要编写 "..\\&.."

如果您想在 replacement 中编写非反向引用字符串 \&,则需要首先转义反斜杠以防止此方法将其解释为反向引用,然后需要再次转义反斜杠以防止字符串字面量消耗它们:"..\\\\&.."

您可能希望使用块形式来避免过多的反斜杠。

哈希 replacement

如果参数 replacement 是一个哈希,并且 pattern 与其键之一匹配,则替换字符串是该键的值

h = {'foo' => 'bar', 'baz' => 'bat'}
'food'.sub('foo', h) # => "bard"

请注意,符号键不匹配

h = {foo: 'bar', baz: 'bat'}
'food'.sub('foo', h) # => "d"

在块形式中,当前匹配的字符串将传递给块;块的返回值将成为替换字符串

s = '@'
'1234'.gsub(/\d/) { |match| s.succ! } # => "ABCD"

诸如 $1$2$`$&$' 之类的特殊匹配变量会被适当地设置。

字符串中的空白

String 类中,空白 被定义为由以下任何混合组成的连续字符序列

  • NL (null):"\x00", "\u0000"

  • HT (水平制表符):"\x09", "\t"

  • LF (换行符):"\x0a", "\n"

  • VT (垂直制表符):"\x0b", "\v"

  • FF (换页符):"\x0c", "\f"

  • CR (回车符):"\x0d", "\r"

  • SP (空格):"\x20", " "

空白与以下方法相关

String 切片

字符串的切片是通过某些条件选择的子字符串。

这些实例方法使用切片

上述每个方法都接受确定要复制或替换的切片的参数。

参数有多种形式。对于字符串 string,形式为

  • string[index]

  • string[start, length]

  • string[range]

  • string[regexp, capture = 0]

  • string[substring]

string[index]

当给定一个非负整数参数 index 时,切片是在字符偏移量 index 处在 self 中找到的 1 个字符的子字符串

'bar'[0]      # => "b"
'bar'[2]      # => "r"
'bar'[20]     # => nil
'тест'[2]     # => "с"
'こんにちは'[4] # => "は"

当给定一个负整数 index 时,切片从通过从 self 的末尾向后计数给定的偏移量处开始

'bar'[-3]      # => "b"
'bar'[-1]      # => "r"
'bar'[-20]     # => nil

string[start, length]

当给定非负整数参数 startlength 时,切片从字符偏移量 start 开始(如果存在),并继续 length 个字符(如果可用)

'foo'[0, 2]      # => "fo"
'тест'[1, 2]     # => "ес"
'こんにちは'[2, 2] # => "にち"
# Zero length.
'foo'[2, 0]      # => ""
# Length not entirely available.
'foo'[1, 200]    # => "oo"
# Start out of range.
'foo'[4, 2]      # => nil

特殊情况:如果 start 等于 self 的长度,则切片是一个新的空字符串

'foo'[3, 2]    # => ""
'foo'[3, 200]  # => ""

当给定负 start 和非负 length 时,切片通过从 self 的末尾向后计数开始,并继续 length 个字符(如果可用)

'foo'[-2, 2]     # => "oo"
'foo'[-2, 200]   # => "oo"
# Start out of range.
'foo'[-4, 2]     # => nil

当给定负 length 时,没有切片

'foo'[1, -1]   # => nil
'foo'[-2, -1]  # => nil

string[range]

当给定 Range 参数 range 时,它会使用 range 中的索引创建一个 string 的子字符串。然后,按照上面的方式确定切片

'foo'[0..1]     # => "fo"
'foo'[0, 2]     # => "fo"

'foo'[2...2]    # => ""
'foo'[2, 0]     # => ""

'foo'[1..200]   # => "oo"
'foo'[1, 200]   # => "oo"

'foo'[4..5]     # => nil
'foo'[4, 2]     # => nil

'foo'[-4..-3]   # => nil
'foo'[-4, 2]    # => nil

'foo'[3..4]     # => ""
'foo'[3, 2]     # => ""

'foo'[-2..-1]   # => "oo"
'foo'[-2, 2]    # => "oo"

'foo'[-2..197]  # => "oo"
'foo'[-2, 200]  # => "oo"

string[regexp, capture = 0]

当给定 Regexp 参数 regexp 并且 capture 参数为 0 时,切片是在 self 中找到的第一个匹配的子字符串

'foo'[/o/]                # => "o"
'foo'[/x/]                # => nil
s = 'hello there'
s[/[aeiou](.)\1/]        # => "ell"
s[/[aeiou](.)\1/, 0]     # => "ell"

如果提供了参数 capture 且不为 0,则它应为捕获组索引(整数)或捕获组名称(StringSymbol);切片是指定的捕获(请参阅 Regexp 中的组和捕获)

s = 'hello there'
s[/[aeiou](.)\1/, 1] # => "l"
s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] # => "l"
s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, :vowel]      # => "e"

如果给定了无效的捕获组索引,则没有切片。如果给定了无效的捕获组名称,则会引发 IndexError

string[substring]

当给定单个 String 参数 substring 时,如果找到该子字符串,则返回 self 中的子字符串,否则返回 nil

'foo'['oo'] # => "oo"
'foo'['xx'] # => nil

本节内容

首先,看看其他地方的内容。String

在这里,String 类提供了以下有用的方法:

用于创建 String 的方法

  • ::new: 返回一个新的字符串。

  • ::try_convert: 返回从给定对象创建的新字符串。

用于冻结/未冻结 String 的方法

  • +@: 返回一个未冻结的字符串:如果 self 未冻结,则返回 self;否则返回 self.dup

  • -@ (别名为 dedup): 返回一个已冻结的字符串:如果 self 已经冻结,则返回 self;否则返回 self.freeze

  • freeze: 如果 self 尚未冻结,则冻结 self;返回 self

用于查询的方法

计数

  • length (别名为 size): 返回字符数(不是字节数)。

  • empty?: 如果 self.length 为零,则返回 true;否则返回 false

  • bytesize: 返回字节数。

  • count: 返回与给定字符串匹配的子字符串计数。

子字符串

  • #=~: 返回与给定 Regexp 或其他对象匹配的第一个子字符串的索引;如果未找到匹配项,则返回 nil

  • index: 返回给定子字符串首次出现的位置的索引;如果未找到,则返回 nil

  • rindex: 返回给定子字符串最后出现的位置的索引;如果未找到,则返回 nil

  • include?: 如果字符串包含给定子字符串,则返回 true;否则返回 false

  • match: 如果字符串与给定 Regexp 匹配,则返回 MatchData 对象;否则返回 nil

  • match?: 如果字符串与给定 Regexp 匹配,则返回 true;否则返回 false

  • start_with?: 如果字符串以任何给定的子字符串开头,则返回 true

  • end_with?: 如果字符串以任何给定的子字符串结尾,则返回 true

编码

  • encoding: 返回表示字符串编码的 Encoding 对象。

  • unicode_normalized?: 如果字符串为 Unicode 规范化形式,则返回 true;否则返回 false

  • valid_encoding?: 如果字符串仅包含对其编码有效的字符,则返回 true

  • ascii_only?: 如果字符串仅包含 ASCII 字符,则返回 true;否则返回 false

其他

  • sum: 返回字符串的基本校验和:每个字节的总和。

  • hash: 返回整数哈希码。

用于比较的方法

  • == (别名为 ===): 如果给定的另一个字符串与 self 具有相同的内容,则返回 true

  • eql?: 如果内容与给定的另一个字符串相同,则返回 true

  • #<=>: 如果给定的另一个字符串小于、等于或大于 self,则返回 -1、0 或 1。

  • casecmp: 忽略大小写,如果给定的另一个字符串小于、等于或大于 self,则返回 -1、0 或 1。

  • casecmp?: 如果字符串在 Unicode 大小写折叠后与给定字符串相等,则返回 true;否则返回 false

用于修改 String 的方法

这些方法中的每一个都会修改 self

插入

  • insert: 返回 self,并在指定的偏移量处插入给定字符串。

  • <<: 返回 self,并与给定字符串或整数连接。

  • append_as_bytes: 返回 self,并连接字符串,而不执行任何编码验证或转换。

替换

  • sub!: 将与给定模式匹配的第一个子字符串替换为给定的替换字符串;如果有任何更改,则返回 self,否则返回 nil

  • gsub!: 将与给定模式匹配的每个子字符串替换为给定的替换字符串;如果有任何更改,则返回 self,否则返回 nil

  • succ! (别名为 next!): 返回 self 修改后的版本,使其成为自己的后继者。

  • initialize_copy (别名为 replace): 返回 self,其全部内容被给定的字符串替换。

  • reverse!: 返回 self,其字符顺序颠倒。

  • setbyte: 将给定整数偏移量处的字节设置为给定值;返回参数。

  • tr!: 将 self 中指定的字符替换为指定的替换字符;如果有任何更改,则返回 self,否则返回 nil

  • tr_s!: 将 self 中指定的字符替换为指定的替换字符,并删除被修改的子字符串中的重复项;如果有任何更改,则返回 self,否则返回 nil

大小写

  • capitalize!: 将首字母大写,其余字母小写;如果有任何更改,则返回 self,否则返回 nil

  • downcase!: 将所有字符小写;如果有任何更改,则返回 self,否则返回 nil

  • upcase!: 将所有字符大写;如果有任何更改,则返回 self,否则返回 nil

  • swapcase!: 将每个小写字符大写,将每个大写字符小写;如果有任何更改,则返回 self,否则返回 nil

编码

  • encode!: 返回 self,其所有字符都从一个编码转码为另一个编码。

  • unicode_normalize!: 将 self Unicode 规范化;返回 self

  • scrub!: 将每个无效字节替换为给定的字符;返回 self

  • force_encoding: 将编码更改为给定的编码;返回 self

删除

  • clear: 删除所有内容,使 self 为空;返回 self

  • slice!, []=: 删除由给定索引、起始/长度、范围、正则表达式或子字符串确定的子字符串。

  • squeeze!: 删除连续重复的字符;返回 self

  • delete!: 删除由子字符串参数的交集确定的字符。

  • lstrip!: 删除前导空格;如果有任何更改,则返回 self,否则返回 nil

  • rstrip!: 删除尾随空格;如果有任何更改,则返回 self,否则返回 nil

  • strip!: 删除前导和尾随空格;如果有任何更改,则返回 self,否则返回 nil

  • chomp!: 删除尾随记录分隔符(如果找到);如果有任何更改,则返回 self,否则返回 nil

  • chop!: 删除尾随换行符(如果找到);否则删除最后一个字符;如果有任何更改,则返回 self,否则返回 nil

用于转换为新 String 的方法

这些方法中的每一个都会基于 self 返回新的 String,通常只是 self 的修改副本。

扩展

  • *: 返回 self 的多个副本的连接。

  • +: 返回 self 和给定的另一个字符串的连接。

  • center: 返回 self 的副本,该副本位于填充子字符串之间居中。

  • concat: 返回 self 与给定的其他字符串的连接。

  • prepend: 返回给定的另一个字符串与 self 的连接。

  • ljust: 返回给定长度的 self 的副本,该副本右侧填充了给定的另一个字符串。

  • rjust: 返回给定长度的 self 的副本,该副本左侧填充了给定的另一个字符串。

编码

  • b: 返回编码为 ASCII-8BIT 的 self 的副本。

  • scrub: 返回 self 的副本,其中每个无效字节都替换为给定的字符。

  • unicode_normalize: 返回 self 的副本,其中每个字符都经过 Unicode 规范化。

  • encode: 返回 self 的副本,其中所有字符都从一个编码转码为另一个编码。

替换

  • dump: 返回 self 的副本,其中所有非打印字符都替换为 xHH 表示法,并且所有特殊字符都已转义。

  • undump: 返回 self 的副本,其中所有 \xNN 表示法都替换为 \uNNNN 表示法,并且所有转义字符都已取消转义。

  • sub: 返回一个 self 的副本,其中第一个与给定模式匹配的子字符串被替换为给定的替换字符串。

  • gsub: 返回一个 self 的副本,其中每个与给定模式匹配的子字符串都被替换为给定的替换字符串。

  • succ (别名为 next): 返回 self 的后继字符串。

  • reverse: 返回一个 self 的副本,其中的字符顺序反转。

  • tr: 返回一个 self 的副本,其中指定的字符被替换为指定的替换字符。

  • tr_s: 返回一个 self 的副本,其中指定的字符被替换为指定的替换字符,并从修改后的子字符串中删除重复项。

  • %: 返回将给定对象格式化为 self 后得到的字符串。

大小写

  • capitalize: 返回一个 self 的副本,其中第一个字符大写,所有其他字符小写。

  • downcase: 返回一个 self 的副本,其中所有字符都小写。

  • upcase: 返回一个 self 的副本,其中所有字符都大写。

  • swapcase: 返回一个 self 的副本,其中所有大写字符都小写,所有小写字符都大写。

删除

  • delete: 返回一个 self 的副本,其中删除了指定的字符。

  • delete_prefix: 返回一个 self 的副本,其中删除了给定的前缀。

  • delete_suffix: 返回一个 self 的副本,其中删除了给定的后缀。

  • lstrip: 返回一个 self 的副本,其中删除了前导空格。

  • rstrip: 返回一个 self 的副本,其中删除了尾随空格。

  • strip: 返回一个 self 的副本,其中删除了前导和尾随空格。

  • chomp: 返回一个 self 的副本,如果找到尾随的记录分隔符,则将其删除。

  • chop: 返回一个 self 的副本,其中删除了尾随的换行符或最后一个字符。

  • squeeze: 返回一个 self 的副本,其中删除了连续的重复字符。

  • [] (别名为 slice): 返回由给定的索引、起始/长度、范围、正则表达式或字符串确定的子字符串。

  • byteslice: 返回由给定的索引、起始/长度或范围确定的子字符串。

  • chr: 返回第一个字符。

复制

  • to_s (别名为 to_str): 如果 selfString 的子类,则返回复制到 String 中的 self;否则,返回 self

转换为非 String 的方法

这些方法中的每一个都将 self 的内容转换为非 String 类型。

字符、字节和群集

  • bytes: 返回 self 中字节的数组。

  • chars: 返回 self 中字符的数组。

  • codepoints: 返回 self 中整数序数的数组。

  • getbyte: 返回 self 中给定索引处的整数字节。

  • grapheme_clusters: 返回 self 中字素群集的数组。

分割

  • lines: 返回 self 中行的数组,由给定的记录分隔符确定。

  • partition: 返回一个由与给定子字符串或正则表达式匹配的第一个子字符串确定的 3 元素数组。

  • rpartition: 返回一个由与给定子字符串或正则表达式匹配的最后一个子字符串确定的 3 元素数组。

  • split: 返回由给定的分隔符(正则表达式或字符串)确定的子字符串数组;或者,如果给定了块,则将这些子字符串传递给该块。

匹配

  • scan: 返回与给定的正则表达式或字符串匹配的子字符串数组;或者,如果给定了块,则将每个匹配的子字符串传递给该块。

  • unpack: 返回根据给定格式从 self 中提取的子字符串数组。

  • unpack1: 返回根据给定格式从 self 中提取的第一个子字符串。

数值

  • hex: 返回前导字符的整数值,解释为十六进制数字。

  • oct: 返回前导字符的整数值,解释为八进制数字。

  • ord: 返回 self 中第一个字符的整数序数。

  • to_i: 返回前导字符的整数值,解释为整数。

  • to_f: 返回前导字符的浮点数值,解释为浮点数。

字符串和符号

  • inspect: 返回一个 self 的副本,用双引号括起来,并转义特殊字符。

  • intern (别名为 to_sym): 返回与 self 对应的符号。

用于迭代的方法

  • each_byte: 用 self 中每个连续的字节调用给定的块。

  • each_char: 用 self 中每个连续的字符调用给定的块。

  • each_codepoint: 用 self 中每个连续的整数码位调用给定的块。

  • each_grapheme_cluster: 用 self 中每个连续的字素群集调用给定的块。

  • each_line: 用 self 中每个连续的行调用给定的块,由给定的记录分隔符确定。

  • upto: 用连续调用 succ 返回的每个字符串值调用给定的块。

公共类方法

new(string = '', **opts) → new_string 点击以切换源

返回一个新的 String,它是 string 的副本。

如果没有参数,则返回编码为 ASCII-8BIT 的空字符串

s = String.new
s # => ""
s.encoding # => #<Encoding:ASCII-8BIT>

如果使用可选参数 string 且没有关键字参数,则返回具有相同编码的 string 的副本

String.new('foo')               # => "foo"
String.new('тест')              # => "тест"
String.new('こんにちは')          # => "こんにちは"

(与 String.new 不同,像 '' 这样的字符串字面量here 文档字面量始终具有脚本编码。)

如果使用可选关键字参数 encoding,则返回具有指定编码的 string 的副本;encoding 可以是 Encoding 对象、编码名称或编码名称别名

String.new('foo', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'US-ASCII').encoding         # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'ASCII').encoding            # => #<Encoding:US-ASCII>

给定的编码不必对字符串的内容有效,并且不会检查其有效性

s = String.new('こんにちは', encoding: 'ascii')
s.valid_encoding? # => false

但是会检查给定的 encoding 本身

String.new('foo', encoding: 'bar') # Raises ArgumentError.

如果使用可选关键字参数 capacity,则返回 string 的副本(如果未给出 string,则返回空字符串);给定的 capacity 仅为建议值,可能设置也可能不设置内部缓冲区的大小,这反过来可能会影响性能

String.new(capacity: 1)
String.new('foo', capacity: 4096)

请注意,Ruby 字符串在内部以 null 结尾,因此内部缓冲区大小将比请求的容量大一个或多个字节,具体取决于编码。

stringencodingcapacity 参数可以一起使用

String.new('hello', encoding: 'UTF-8', capacity: 25)
static VALUE
rb_str_init(int argc, VALUE *argv, VALUE str)
{
    static ID keyword_ids[2];
    VALUE orig, opt, venc, vcapa;
    VALUE kwargs[2];
    rb_encoding *enc = 0;
    int n;

    if (!keyword_ids[0]) {
        keyword_ids[0] = rb_id_encoding();
        CONST_ID(keyword_ids[1], "capacity");
    }

    n = rb_scan_args(argc, argv, "01:", &orig, &opt);
    if (!NIL_P(opt)) {
        rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
        venc = kwargs[0];
        vcapa = kwargs[1];
        if (!UNDEF_P(venc) && !NIL_P(venc)) {
            enc = rb_to_encoding(venc);
        }
        if (!UNDEF_P(vcapa) && !NIL_P(vcapa)) {
            long capa = NUM2LONG(vcapa);
            long len = 0;
            int termlen = enc ? rb_enc_mbminlen(enc) : 1;

            if (capa < STR_BUF_MIN_SIZE) {
                capa = STR_BUF_MIN_SIZE;
            }
            if (n == 1) {
                StringValue(orig);
                len = RSTRING_LEN(orig);
                if (capa < len) {
                    capa = len;
                }
                if (orig == str) n = 0;
            }
            str_modifiable(str);
            if (STR_EMBED_P(str) || FL_TEST(str, STR_SHARED|STR_NOFREE)) {
                /* make noembed always */
                const size_t size = (size_t)capa + termlen;
                const char *const old_ptr = RSTRING_PTR(str);
                const size_t osize = RSTRING_LEN(str) + TERM_LEN(str);
                char *new_ptr = ALLOC_N(char, size);
                if (STR_EMBED_P(str)) RUBY_ASSERT((long)osize <= str_embed_capa(str));
                memcpy(new_ptr, old_ptr, osize < size ? osize : size);
                FL_UNSET_RAW(str, STR_SHARED|STR_NOFREE);
                RSTRING(str)->as.heap.ptr = new_ptr;
            }
            else if (STR_HEAP_SIZE(str) != (size_t)capa + termlen) {
                SIZED_REALLOC_N(RSTRING(str)->as.heap.ptr, char,
                        (size_t)capa + termlen, STR_HEAP_SIZE(str));
            }
            STR_SET_LEN(str, len);
            TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen);
            if (n == 1) {
                memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len);
                rb_enc_cr_str_exact_copy(str, orig);
            }
            FL_SET(str, STR_NOEMBED);
            RSTRING(str)->as.heap.aux.capa = capa;
        }
        else if (n == 1) {
            rb_str_replace(str, orig);
        }
        if (enc) {
            rb_enc_associate(str, enc);
            ENC_CODERANGE_CLEAR(str);
        }
    }
    else if (n == 1) {
        rb_str_replace(str, orig);
    }
    return str;
}
try_convert(object) → object, new_string, or nil 点击以切换源

如果 object 是一个 String 对象,则返回 object

否则,如果 object 响应 :to_str,则调用 object.to_str 并返回结果。

如果 object 不响应 :to_str,则返回 nil

除非 object.to_str 返回 String 对象,否则会引发异常。

static VALUE
rb_str_s_try_convert(VALUE dummy, VALUE str)
{
    return rb_check_string_type(str);
}

公共实例方法

string % object → new_string 点击以切换源

返回将 object 格式化为格式规范 self 的结果(有关格式化详细信息,请参阅 Kernel#sprintf

"%05d" % 123 # => "00123"

如果 self 包含多个替换项,则 object 必须是包含要替换的值的 ArrayHash

"%-5s: %016x" % [ "ID", self.object_id ] # => "ID   : 00002b054ec93168"
"foo = %{foo}" % {foo: 'bar'} # => "foo = bar"
"foo = %{foo}, baz = %{baz}" % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat"
static VALUE
rb_str_format_m(VALUE str, VALUE arg)
{
    VALUE tmp = rb_check_array_type(arg);

    if (!NIL_P(tmp)) {
        return rb_str_format(RARRAY_LENINT(tmp), RARRAY_CONST_PTR(tmp), str);
    }
    return rb_str_format(1, &arg, str);
}
string * integer → new_string 点击以切换源

返回一个新的 String,其中包含 selfinteger 个副本

"Ho! " * 3 # => "Ho! Ho! Ho! "
"Ho! " * 0 # => ""
VALUE
rb_str_times(VALUE str, VALUE times)
{
    VALUE str2;
    long n, len;
    char *ptr2;
    int termlen;

    if (times == INT2FIX(1)) {
        return str_duplicate(rb_cString, str);
    }
    if (times == INT2FIX(0)) {
        str2 = str_alloc_embed(rb_cString, 0);
        rb_enc_copy(str2, str);
        return str2;
    }
    len = NUM2LONG(times);
    if (len < 0) {
        rb_raise(rb_eArgError, "negative argument");
    }
    if (RSTRING_LEN(str) == 1 && RSTRING_PTR(str)[0] == 0) {
        if (STR_EMBEDDABLE_P(len, 1)) {
            str2 = str_alloc_embed(rb_cString, len + 1);
            memset(RSTRING_PTR(str2), 0, len + 1);
        }
        else {
            str2 = str_alloc_heap(rb_cString);
            RSTRING(str2)->as.heap.aux.capa = len;
            RSTRING(str2)->as.heap.ptr = ZALLOC_N(char, (size_t)len + 1);
        }
        STR_SET_LEN(str2, len);
        rb_enc_copy(str2, str);
        return str2;
    }
    if (len && LONG_MAX/len <  RSTRING_LEN(str)) {
        rb_raise(rb_eArgError, "argument too big");
    }

    len *= RSTRING_LEN(str);
    termlen = TERM_LEN(str);
    str2 = str_enc_new(rb_cString, 0, len, STR_ENC_GET(str));
    ptr2 = RSTRING_PTR(str2);
    if (len) {
        n = RSTRING_LEN(str);
        memcpy(ptr2, RSTRING_PTR(str), n);
        while (n <= len/2) {
            memcpy(ptr2 + n, ptr2, n);
            n *= 2;
        }
        memcpy(ptr2 + n, ptr2, len-n);
    }
    STR_SET_LEN(str2, len);
    TERM_FILL(&ptr2[len], termlen);
    rb_enc_cr_str_copy_for_substr(str2, str);

    return str2;
}
string + other_string → new_string 点击以切换源

返回一个新的 String,其中包含与 self 连接的 other_string

"Hello from " + self.to_s # => "Hello from main"
VALUE
rb_str_plus(VALUE str1, VALUE str2)
{
    VALUE str3;
    rb_encoding *enc;
    char *ptr1, *ptr2, *ptr3;
    long len1, len2;
    int termlen;

    StringValue(str2);
    enc = rb_enc_check_str(str1, str2);
    RSTRING_GETMEM(str1, ptr1, len1);
    RSTRING_GETMEM(str2, ptr2, len2);
    termlen = rb_enc_mbminlen(enc);
    if (len1 > LONG_MAX - len2) {
        rb_raise(rb_eArgError, "string size too big");
    }
    str3 = str_enc_new(rb_cString, 0, len1+len2, enc);
    ptr3 = RSTRING_PTR(str3);
    memcpy(ptr3, ptr1, len1);
    memcpy(ptr3+len1, ptr2, len2);
    TERM_FILL(&ptr3[len1+len2], termlen);

    ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
                           ENC_CODERANGE_AND(ENC_CODERANGE(str1), ENC_CODERANGE(str2)));
    RB_GC_GUARD(str1);
    RB_GC_GUARD(str2);
    return str3;
}
+string → new_string or self 点击以切换源

如果 self 未冻结并且可以在不发出警告的情况下发生突变,则返回 self

否则,返回未冻结的 self.dup

static VALUE
str_uplus(VALUE str)
{
    if (OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
        return rb_str_dup(str);
    }
    else {
        return str;
    }
}
-string → frozen_string 点击以切换源

返回字符串的冻结的、可能预先存在的副本。

只要返回的 String 没有在其上设置任何实例变量并且不是 String 子类,就会对其进行重复数据删除。

请注意,-string 变体更方便用于定义常量

FILENAME = -'config/database.yml'

dedup 更适合在计算链中使用该方法

@url_list.concat(urls.map(&:dedup))
static VALUE
str_uminus(VALUE str)
{
    if (!BARE_STRING_P(str) && !rb_obj_frozen_p(str)) {
        str = rb_str_dup(str);
    }
    return rb_fstring(str);
}
也别名为:dedup
string << object → string 点击以切换源

object 连接到 self 并返回 self

s = 'foo'
s << 'bar' # => "foobar"
s          # => "foobar"

如果 object 是一个 Integer,则该值被视为代码点,并在连接之前转换为字符

s = 'foo'
s << 33 # => "foo!"

如果该代码点不能以 *string* 的编码表示,则会引发 RangeError

s = 'foo'
s.encoding              # => <Encoding:UTF-8>
s << 0x00110000         # 1114112 out of char range (RangeError)
s = 'foo'.encode('EUC-JP')
s << 0x00800080         # invalid codepoint 0x800080 in EUC-JP (RangeError)

如果编码为 US-ASCII 且代码点为 0..0xff,则 *string* 会自动提升为 ASCII-8BIT。

s = 'foo'.encode('US-ASCII')
s << 0xff
s.encoding              # => #<Encoding:BINARY (ASCII-8BIT)>

相关:String#concat,它接受多个参数。

VALUE
rb_str_concat(VALUE str1, VALUE str2)
{
    unsigned int code;
    rb_encoding *enc = STR_ENC_GET(str1);
    int encidx;

    if (RB_INTEGER_TYPE_P(str2)) {
        if (rb_num_to_uint(str2, &code) == 0) {
        }
        else if (FIXNUM_P(str2)) {
            rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2));
        }
        else {
            rb_raise(rb_eRangeError, "bignum out of char range");
        }
    }
    else {
        return rb_str_append(str1, str2);
    }

    encidx = rb_ascii8bit_appendable_encoding_index(enc, code);

    if (encidx >= 0) {
        rb_str_buf_cat_byte(str1, (unsigned char)code);
    }
    else {
        long pos = RSTRING_LEN(str1);
        int cr = ENC_CODERANGE(str1);
        int len;
        char *buf;

        switch (len = rb_enc_codelen(code, enc)) {
          case ONIGERR_INVALID_CODE_POINT_VALUE:
            rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
            break;
          case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
          case 0:
            rb_raise(rb_eRangeError, "%u out of char range", code);
            break;
        }
        buf = ALLOCA_N(char, len + 1);
        rb_enc_mbcput(code, buf, enc);
        if (rb_enc_precise_mbclen(buf, buf + len + 1, enc) != len) {
            rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
        }
        rb_str_resize(str1, pos+len);
        memcpy(RSTRING_PTR(str1) + pos, buf, len);
        if (cr == ENC_CODERANGE_7BIT && code > 127) {
            cr = ENC_CODERANGE_VALID;
        }
        else if (cr == ENC_CODERANGE_BROKEN) {
            cr = ENC_CODERANGE_UNKNOWN;
        }
        ENC_CODERANGE_SET(str1, cr);
    }
    return str1;
}
string <=> other_string → -1, 0, 1, or nil 点击以切换源

比较 selfother_string,返回

  • 如果 other_string 较大,则返回 -1。

  • 如果两者相等,则返回 0。

  • 如果 other_string 较小,则返回 1。

  • 如果两者无法比较,则返回 nil

示例

'foo' <=> 'foo' # => 0
'foo' <=> 'food' # => -1
'food' <=> 'foo' # => 1
'FOO' <=> 'foo' # => -1
'foo' <=> 'FOO' # => 1
'foo' <=> 1 # => nil
static VALUE
rb_str_cmp_m(VALUE str1, VALUE str2)
{
    int result;
    VALUE s = rb_check_string_type(str2);
    if (NIL_P(s)) {
        return rb_invcmp(str1, str2);
    }
    result = rb_str_cmp(str1, s);
    return INT2FIX(result);
}
string == object → true 或 false 点击切换源代码

如果 object 具有与 self 相同的长度和内容,则返回 true;否则返回 false

s = 'foo'
s == 'foo' # => true
s == 'food' # => false
s == 'FOO' # => false

如果两个字符串的编码不兼容,则返回 false

"\u{e4 f6 fc}".encode("ISO-8859-1") == ("\u{c4 d6 dc}") # => false

如果 object 不是 String 的实例,但响应 to_str,则使用 object.== 比较这两个字符串。

VALUE
rb_str_equal(VALUE str1, VALUE str2)
{
    if (str1 == str2) return Qtrue;
    if (!RB_TYPE_P(str2, T_STRING)) {
        if (!rb_respond_to(str2, idTo_str)) {
            return Qfalse;
        }
        return rb_equal(str2, str1);
    }
    return rb_str_eql_internal(str1, str2);
}
也别名为:===
string === object → true 或 false

如果 object 具有与 self 相同的长度和内容,则返回 true;否则返回 false

s = 'foo'
s == 'foo' # => true
s == 'food' # => false
s == 'FOO' # => false

如果两个字符串的编码不兼容,则返回 false

"\u{e4 f6 fc}".encode("ISO-8859-1") == ("\u{c4 d6 dc}") # => false

如果 object 不是 String 的实例,但响应 to_str,则使用 object.== 比较这两个字符串。

别名为:==
string =~ regexp → integer 或 nil 点击切换源代码
string =~ object → integer 或 nil

返回与给定 regexp 匹配的第一个子字符串的 Integer 索引,如果未找到匹配项,则返回 nil

'foo' =~ /f/ # => 0
'foo' =~ /o/ # => 1
'foo' =~ /x/ # => nil

注意:还会更新 Regexp 的全局变量

如果给定的 object 不是 Regexp,则返回 object =~ self 返回的值。

请注意,string =~ regexpregexp =~ string 不同(请参阅 Regexp#=~)。

number= nil
"no. 9" =~ /(?<number>\d+)/
number # => nil (not assigned)
/(?<number>\d+)/ =~ "no. 9"
number #=> "9"
static VALUE
rb_str_match(VALUE x, VALUE y)
{
    switch (OBJ_BUILTIN_TYPE(y)) {
      case T_STRING:
        rb_raise(rb_eTypeError, "type mismatch: String given");

      case T_REGEXP:
        return rb_reg_match(y, x);

      default:
        return rb_funcall(y, idEqTilde, 1, x);
    }
}
string[index] → new_string 或 nil 点击切换源代码
string[start, length] → new_string 或 nil
string[range] → new_string 或 nil
string[regexp, capture = 0] → new_string 或 nil
string[substring] → new_string 或 nil

返回由参数指定的 self 的子字符串。请参阅 字符串切片中的示例。

static VALUE
rb_str_aref_m(int argc, VALUE *argv, VALUE str)
{
    if (argc == 2) {
        if (RB_TYPE_P(argv[0], T_REGEXP)) {
            return rb_str_subpat(str, argv[0], argv[1]);
        }
        else {
            return rb_str_substr_two_fixnums(str, argv[0], argv[1], TRUE);
        }
    }
    rb_check_arity(argc, 1, 2);
    return rb_str_aref(str, argv[0]);
}
也别名为:slice
string[index] = new_string 点击切换源代码
string[start, length] = new_string
string[range] = new_string
string[regexp, capture = 0] = new_string
string[substring] = new_string

替换 self 的全部、部分或没有内容;返回 new_string。请参阅 字符串切片

一些示例

s = 'foo'
s[2] = 'rtune'     # => "rtune"
s                  # => "fortune"
s[1, 5] = 'init'   # => "init"
s                  # => "finite"
s[3..4] = 'al'     # => "al"
s                  # => "finale"
s[/e$/] = 'ly'     # => "ly"
s                  # => "finally"
s['lly'] = 'ncial' # => "ncial"
s                  # => "financial"
static VALUE
rb_str_aset_m(int argc, VALUE *argv, VALUE str)
{
    if (argc == 3) {
        if (RB_TYPE_P(argv[0], T_REGEXP)) {
            rb_str_subpat_set(str, argv[0], argv[1], argv[2]);
        }
        else {
            rb_str_update(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
        }
        return argv[2];
    }
    rb_check_arity(argc, 2, 3);
    return rb_str_aset(str, argv[0], argv[1]);
}
append_as_bytes(*objects) → string 点击切换源代码

objects 中的每个对象连接到 self 中,不进行任何编码验证或转换,并返回 self

s = 'foo'
s.append_as_bytes(" \xE2\x82")  # => "foo \xE2\x82"
s.valid_encoding?               # => false
s.append_as_bytes("\xAC 12")
s.valid_encoding?               # => true

对于每个给定的对象 object,如果它是 Integer,则该值被视为一个字节。如果 Integer 大于一个字节,则只考虑低位字节,类似于 String#setbyte

s = ""
s.append_as_bytes(0, 257)             # =>  "\u0000\u0001"

相关:String#<<String#concat,它们进行编码感知连接。

VALUE
rb_str_append_as_bytes(int argc, VALUE *argv, VALUE str)
{
    long needed_capacity = 0;
    volatile VALUE t0;
    enum ruby_value_type *types = ALLOCV_N(enum ruby_value_type, t0, argc);

    for (int index = 0; index < argc; index++) {
        VALUE obj = argv[index];
        enum ruby_value_type type = types[index] = rb_type(obj);
        switch (type) {
          case T_FIXNUM:
          case T_BIGNUM:
            needed_capacity++;
            break;
          case T_STRING:
            needed_capacity += RSTRING_LEN(obj);
            break;
          default:
            rb_raise(
                rb_eTypeError,
                "wrong argument type %"PRIsVALUE" (expected String or Integer)",
                rb_obj_class(obj)
            );
            break;
        }
    }

    str_ensure_available_capa(str, needed_capacity);
    char *sptr = RSTRING_END(str);

    for (int index = 0; index < argc; index++) {
        VALUE obj = argv[index];
        enum ruby_value_type type = types[index];
        switch (type) {
          case T_FIXNUM:
          case T_BIGNUM: {
            argv[index] = obj = rb_int_and(obj, INT2FIX(0xff));
            char byte = (char)(NUM2INT(obj) & 0xFF);
            *sptr = byte;
            sptr++;
            break;
          }
          case T_STRING: {
            const char *ptr;
            long len;
            RSTRING_GETMEM(obj, ptr, len);
            memcpy(sptr, ptr, len);
            sptr += len;
            break;
          }
          default:
            rb_bug("append_as_bytes arguments should have been validated");
        }
    }

    STR_SET_LEN(str, RSTRING_LEN(str) + needed_capacity);
    TERM_FILL(sptr, TERM_LEN(str)); /* sentinel */

    int cr = ENC_CODERANGE(str);
    switch (cr) {
      case ENC_CODERANGE_7BIT: {
        for (int index = 0; index < argc; index++) {
            VALUE obj = argv[index];
            enum ruby_value_type type = types[index];
            switch (type) {
              case T_FIXNUM:
              case T_BIGNUM: {
                if (!ISASCII(NUM2INT(obj))) {
                    goto clear_cr;
                }
                break;
              }
              case T_STRING: {
                if (ENC_CODERANGE(obj) != ENC_CODERANGE_7BIT) {
                    goto clear_cr;
                }
                break;
              }
              default:
                rb_bug("append_as_bytes arguments should have been validated");
            }
        }
        break;
      }
      case ENC_CODERANGE_VALID:
        if (ENCODING_GET_INLINED(str) == ENCINDEX_ASCII_8BIT) {
            goto keep_cr;
        }
        else {
            goto clear_cr;
        }
        break;
      default:
        goto clear_cr;
        break;
    }

    RB_GC_GUARD(t0);

  clear_cr:
    // If no fast path was hit, we clear the coderange.
    // append_as_bytes is predominently meant to be used in
    // buffering situation, hence it's likely the coderange
    // will never be scanned, so it's not worth spending time
    // precomputing the coderange except for simple and common
    // situations.
    ENC_CODERANGE_CLEAR(str);
  keep_cr:
    return str;
}
ascii_only? → true 或 false 点击切换源代码

如果 self 仅包含 ASCII 字符,则返回 true,否则返回 false

'abc'.ascii_only?         # => true
"abc\u{6666}".ascii_only? # => false
static VALUE
rb_str_is_ascii_only_p(VALUE str)
{
    int cr = rb_enc_str_coderange(str);

    return RBOOL(cr == ENC_CODERANGE_7BIT);
}
b → string 点击切换源代码

返回一个 self 的副本,该副本具有 ASCII-8BIT 编码;底层字节不会被修改。

s = "\x99"
s.encoding   # => #<Encoding:UTF-8>
t = s.b      # => "\x99"
t.encoding   # => #<Encoding:ASCII-8BIT>

s = "\u4095" # => "䂕"
s.encoding   # => #<Encoding:UTF-8>
s.bytes      # => [228, 130, 149]
t = s.b      # => "\xE4\x82\x95"
t.encoding   # => #<Encoding:ASCII-8BIT>
t.bytes      # => [228, 130, 149]
static VALUE
rb_str_b(VALUE str)
{
    VALUE str2;
    if (STR_EMBED_P(str)) {
        str2 = str_alloc_embed(rb_cString, RSTRING_LEN(str) + TERM_LEN(str));
    }
    else {
        str2 = str_alloc_heap(rb_cString);
    }
    str_replace_shared_without_enc(str2, str);

    if (rb_enc_asciicompat(STR_ENC_GET(str))) {
        // BINARY strings can never be broken; they're either 7-bit ASCII or VALID.
        // If we know the receiver's code range then we know the result's code range.
        int cr = ENC_CODERANGE(str);
        switch (cr) {
          case ENC_CODERANGE_7BIT:
            ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT);
            break;
          case ENC_CODERANGE_BROKEN:
          case ENC_CODERANGE_VALID:
            ENC_CODERANGE_SET(str2, ENC_CODERANGE_VALID);
            break;
          default:
            ENC_CODERANGE_CLEAR(str2);
            break;
        }
    }

    return str2;
}
byteindex(substring, offset = 0) → integer 或 nil 点击切换源代码
byteindex(regexp, offset = 0) → integer 或 nil

返回给定 substring 的第一个出现的基于字节的 Integer 索引,如果未找到,则返回 nil

'foo'.byteindex('f') # => 0
'foo'.byteindex('o') # => 1
'foo'.byteindex('oo') # => 1
'foo'.byteindex('ooo') # => nil

返回给定 Regexp regexp 的第一个匹配项的基于字节的 Integer 索引,如果未找到,则返回 nil

'foo'.byteindex(/f/) # => 0
'foo'.byteindex(/o/) # => 1
'foo'.byteindex(/oo/) # => 1
'foo'.byteindex(/ooo/) # => nil

如果给定了 Integer 参数 offset,则它指定字符串中开始搜索的基于字节的位置。

'foo'.byteindex('o', 1) # => 1
'foo'.byteindex('o', 2) # => 2
'foo'.byteindex('o', 3) # => nil

如果 offset 为负数,则从 self 的末尾向后计数。

'foo'.byteindex('o', -1) # => 2
'foo'.byteindex('o', -2) # => 1
'foo'.byteindex('o', -3) # => 1
'foo'.byteindex('o', -4) # => nil

如果 offset 没有落在字符(代码点)边界上,则会引发 IndexError

相关:String#indexString#byterindex

static VALUE
rb_str_byteindex_m(int argc, VALUE *argv, VALUE str)
{
    VALUE sub;
    VALUE initpos;
    long pos;

    if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
        long slen = RSTRING_LEN(str);
        pos = NUM2LONG(initpos);
        if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
            if (RB_TYPE_P(sub, T_REGEXP)) {
                rb_backref_set(Qnil);
            }
            return Qnil;
        }
    }
    else {
        pos = 0;
    }

    str_ensure_byte_pos(str, pos);

    if (RB_TYPE_P(sub, T_REGEXP)) {
        if (rb_reg_search(sub, str, pos, 0) >= 0) {
            VALUE match = rb_backref_get();
            struct re_registers *regs = RMATCH_REGS(match);
            pos = BEG(0);
            return LONG2NUM(pos);
        }
    }
    else {
        StringValue(sub);
        pos = rb_str_byteindex(str, sub, pos);
        if (pos >= 0) return LONG2NUM(pos);
    }
    return Qnil;
}
byterindex(substring, offset = self.bytesize) → integer 或 nil 点击切换源代码
byterindex(regexp, offset = self.bytesize) → integer 或 nil

返回给定 substring 的 _最后_ 一次出现的基于字节的 Integer 索引,如果未找到,则返回 nil

'foo'.byterindex('f') # => 0
'foo'.byterindex('o') # => 2
'foo'.byterindex('oo') # => 1
'foo'.byterindex('ooo') # => nil

返回给定 Regexp regexp 的 _最后_ 一次匹配项的基于字节的 Integer 索引,如果未找到,则返回 nil

'foo'.byterindex(/f/) # => 0
'foo'.byterindex(/o/) # => 2
'foo'.byterindex(/oo/) # => 1
'foo'.byterindex(/ooo/) # => nil

_最后_ 一次匹配是指从可能的最后位置开始,而不是最长的匹配项的最后一次。

'foo'.byterindex(/o+/) # => 2
$~ #=> #<MatchData "o">

要获得最长的最后一次匹配,需要与负向后查找结合使用。

'foo'.byterindex(/(?<!o)o+/) # => 1
$~ #=> #<MatchData "oo">

或者使用 String#byteindex 和负向前查找。

'foo'.byteindex(/o+(?!.*o)/) # => 1
$~ #=> #<MatchData "oo">

如果给定且非负,Integer 参数 offset 指定字符串中 _结束_ 搜索的最大起始基于字节的位置。

'foo'.byterindex('o', 0) # => nil
'foo'.byterindex('o', 1) # => 1
'foo'.byterindex('o', 2) # => 2
'foo'.byterindex('o', 3) # => 2

如果 offset 是一个负数 Integer,则字符串中 _结束_ 搜索的最大起始位置是字符串的长度与 offset 的和。

'foo'.byterindex('o', -1) # => 2
'foo'.byterindex('o', -2) # => 1
'foo'.byterindex('o', -3) # => nil
'foo'.byterindex('o', -4) # => nil

如果 offset 没有落在字符(代码点)边界上,则会引发 IndexError

相关:String#byteindex

static VALUE
rb_str_byterindex_m(int argc, VALUE *argv, VALUE str)
{
    VALUE sub;
    VALUE initpos;
    long pos, len = RSTRING_LEN(str);

    if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
        pos = NUM2LONG(initpos);
        if (pos < 0 && (pos += len) < 0) {
            if (RB_TYPE_P(sub, T_REGEXP)) {
                rb_backref_set(Qnil);
            }
            return Qnil;
        }
        if (pos > len) pos = len;
    }
    else {
        pos = len;
    }

    str_ensure_byte_pos(str, pos);

    if (RB_TYPE_P(sub, T_REGEXP)) {
        if (rb_reg_search(sub, str, pos, 1) >= 0) {
            VALUE match = rb_backref_get();
            struct re_registers *regs = RMATCH_REGS(match);
            pos = BEG(0);
            return LONG2NUM(pos);
        }
    }
    else {
        StringValue(sub);
        pos = rb_str_byterindex(str, sub, pos);
        if (pos >= 0) return LONG2NUM(pos);
    }
    return Qnil;
}
bytes → array_of_bytes 点击切换源代码

返回 self 中字节的数组。

'hello'.bytes # => [104, 101, 108, 108, 111]
'тест'.bytes  # => [209, 130, 208, 181, 209, 129, 209, 130]
'こんにちは'.bytes
# => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
static VALUE
rb_str_bytes(VALUE str)
{
    VALUE ary = WANTARRAY("bytes", RSTRING_LEN(str));
    return rb_str_enumerate_bytes(str, ary);
}
bytesize → integer 点击切换源代码

返回 self 中字节数(而不是字符数)。

'foo'.bytesize        # => 3
'тест'.bytesize       # => 8
'こんにちは'.bytesize   # => 15

String#length 进行比较。

'foo'.length       # => 3
'тест'.length      # => 4
'こんにちは'.length  # => 5
VALUE
rb_str_bytesize(VALUE str)
{
    return LONG2NUM(RSTRING_LEN(str));
}
byteslice(index, length = 1) → string 或 nil 点击切换源代码
byteslice(range) → string 或 nil

返回 self 的子字符串,如果无法构造子字符串,则返回 nil

如果给定了整数参数 indexlength,则返回从给定 index 开始的给定 length 的子字符串(如果可能),如果 length 为负数或 index 超出 self 范围,则返回 nil

s = '0123456789' # => "0123456789"
s.byteslice(2)   # => "2"
s.byteslice(200) # => nil
s.byteslice(4, 3)  # => "456"
s.byteslice(4, 30) # => "456789"
s.byteslice(4, -1) # => nil
s.byteslice(40, 2) # => nil

在以上任一情况下,如果 index 为负数,则从 self 的末尾向后计数。

s = '0123456789'   # => "0123456789"
s.byteslice(-4)    # => "6"
s.byteslice(-4, 3) # => "678"

如果给定了 Range 参数 range,则返回 byteslice(range.begin, range.size)

s = '0123456789'    # => "0123456789"
s.byteslice(4..6)   # => "456"
s.byteslice(-6..-4) # => "456"
s.byteslice(5..2)   # => "" # range.size is zero.
s.byteslice(40..42) # => nil

在所有情况下,返回的字符串都具有与 self 相同的编码。

s.encoding              # => #<Encoding:UTF-8>
s.byteslice(4).encoding # => #<Encoding:UTF-8>
static VALUE
rb_str_byteslice(int argc, VALUE *argv, VALUE str)
{
    if (argc == 2) {
        long beg = NUM2LONG(argv[0]);
        long len = NUM2LONG(argv[1]);
        return str_byte_substr(str, beg, len, TRUE);
    }
    rb_check_arity(argc, 1, 2);
    return str_byte_aref(str, argv[0]);
}
bytesplice(index, length, str) → string 点击切换源代码
bytesplice(index, length, str, str_index, str_length) → string
bytesplice(range, str) → string
bytesplice(range, str, str_range) → string

self 的部分或全部内容替换为 str,并返回 self。受影响的字符串部分使用与 String#byteslice 相同的标准确定,但不能省略 length。如果替换字符串的长度与要替换的文本的长度不同,则将相应地调整字符串。

如果给定了 str_indexstr_length,或者 str_range,则 self 的内容将替换为 str.byteslice(str_index, str_length) 或 str.byteslice(str_range);但是,str 的子字符串不会作为新字符串分配。

接受 Integer 的形式如果值超出范围,则会引发 IndexErrorRange 形式会引发 RangeError。如果起始或结束偏移量没有落在字符(代码点)边界上,则会引发 IndexError

static VALUE
rb_str_bytesplice(int argc, VALUE *argv, VALUE str)
{
    long beg, len, vbeg, vlen;
    VALUE val;
    int cr;

    rb_check_arity(argc, 2, 5);
    if (!(argc == 2 || argc == 3 || argc == 5)) {
        rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3, or 5)", argc);
    }
    if (argc == 2 || (argc == 3 && !RB_INTEGER_TYPE_P(argv[0]))) {
        if (!rb_range_beg_len(argv[0], &beg, &len, RSTRING_LEN(str), 2)) {
            rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
                     rb_builtin_class_name(argv[0]));
        }
        val = argv[1];
        StringValue(val);
        if (argc == 2) {
            /* bytesplice(range, str) */
            vbeg = 0;
            vlen = RSTRING_LEN(val);
        }
        else {
            /* bytesplice(range, str, str_range) */
            if (!rb_range_beg_len(argv[2], &vbeg, &vlen, RSTRING_LEN(val), 2)) {
                rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
                         rb_builtin_class_name(argv[2]));
            }
        }
    }
    else {
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        val = argv[2];
        StringValue(val);
        if (argc == 3) {
            /* bytesplice(index, length, str) */
            vbeg = 0;
            vlen = RSTRING_LEN(val);
        }
        else {
            /* bytesplice(index, length, str, str_index, str_length) */
            vbeg = NUM2LONG(argv[3]);
            vlen = NUM2LONG(argv[4]);
        }
    }
    str_check_beg_len(str, &beg, &len);
    str_check_beg_len(val, &vbeg, &vlen);
    str_modify_keep_cr(str);

    if (RB_UNLIKELY(ENCODING_GET_INLINED(str) != ENCODING_GET_INLINED(val))) {
        rb_enc_associate(str, rb_enc_check(str, val));
    }

    rb_str_update_1(str, beg, len, val, vbeg, vlen);
    cr = ENC_CODERANGE_AND(ENC_CODERANGE(str), ENC_CODERANGE(val));
    if (cr != ENC_CODERANGE_BROKEN)
        ENC_CODERANGE_SET(str, cr);
    return str;
}
capitalize(*options) → string 点击切换源代码

返回一个包含 self 中字符的字符串;第一个字符变为大写;其余字符变为小写。

s = 'hello World!' # => "hello World!"
s.capitalize       # => "Hello world!"

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关:String#capitalize!

static VALUE
rb_str_capitalize(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;
    VALUE ret;

    flags = check_case_options(argc, argv, flags);
    enc = str_true_enc(str);
    if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str;
    if (flags&ONIGENC_CASE_ASCII_ONLY) {
        ret = rb_str_new(0, RSTRING_LEN(str));
        rb_str_ascii_casemap(str, ret, &flags, enc);
    }
    else {
        ret = rb_str_casemap(str, &flags, enc);
    }
    return ret;
}
capitalize!(*options) → self 或 nil 点击切换源代码

self 中的第一个字符变为大写;将其余字符变为小写;如果进行了任何更改,则返回 self,否则返回 nil

s = 'hello World!' # => "hello World!"
s.capitalize!      # => "Hello world!"
s                  # => "Hello world!"
s.capitalize!      # => nil

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关:String#capitalize

static VALUE
rb_str_capitalize_bang(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_TITLECASE;

    flags = check_case_options(argc, argv, flags);
    str_modify_keep_cr(str);
    enc = str_true_enc(str);
    if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
    if (flags&ONIGENC_CASE_ASCII_ONLY)
        rb_str_ascii_casemap(str, str, &flags, enc);
    else
        str_shared_replace(str, rb_str_casemap(str, &flags, enc));

    if (ONIGENC_CASE_MODIFIED&flags) return str;
    return Qnil;
}
casecmp(other_string) → -1、0、1 或 nil 点击切换源代码

比较 self.downcaseother_string.downcase;返回:

  • 如果 other_string.downcase 较大,则返回 -1。

  • 如果两者相等,则返回 0。

  • 如果 other_string.downcase 较小,则返回 1。

  • 如果两者无法比较,则返回 nil

示例

'foo'.casecmp('foo') # => 0
'foo'.casecmp('food') # => -1
'food'.casecmp('foo') # => 1
'FOO'.casecmp('foo') # => 0
'foo'.casecmp('FOO') # => 0
'foo'.casecmp(1) # => nil

请参阅 大小写映射

相关:String#casecmp?

static VALUE
rb_str_casecmp(VALUE str1, VALUE str2)
{
    VALUE s = rb_check_string_type(str2);
    if (NIL_P(s)) {
        return Qnil;
    }
    return str_casecmp(str1, s);
}
casecmp?(other_string) → true、false 或 nil 点击切换源代码

如果 selfother_string 在 Unicode 大小写折叠后相等,则返回 true,否则返回 false

'foo'.casecmp?('foo') # => true
'foo'.casecmp?('food') # => false
'food'.casecmp?('foo') # => false
'FOO'.casecmp?('foo') # => true
'foo'.casecmp?('FOO') # => true

如果两个值无法比较,则返回 nil

'foo'.casecmp?(1) # => nil

请参阅 大小写映射

相关:String#casecmp

static VALUE
rb_str_casecmp_p(VALUE str1, VALUE str2)
{
    VALUE s = rb_check_string_type(str2);
    if (NIL_P(s)) {
        return Qnil;
    }
    return str_casecmp_p(str1, s);
}
center(size, pad_string = ' ') → new_string 点击切换源代码

返回 self 的居中副本。

如果整数参数 size 大于 self 的大小(以字符为单位),则返回长度为 size 的新字符串,该字符串是 self 的副本,在两端居中并使用 pad_string 填充。

'hello'.center(10)       # => "  hello   "
'  hello'.center(10)     # => "   hello  "
'hello'.center(10, 'ab') # => "abhelloaba"
'тест'.center(10)        # => "   тест   "
'こんにちは'.center(10)    # => "  こんにちは   "

如果 size 不大于 self 的大小,则返回 self 的副本。

'hello'.center(5)  # => "hello"
'hello'.center(1)  # => "hello"

相关:String#ljustString#rjust

static VALUE
rb_str_center(int argc, VALUE *argv, VALUE str)
{
    return rb_str_justify(argc, argv, str, 'c');
}
chars → array_of_characters 点击切换源代码

返回 self 中字符的数组。

'hello'.chars     # => ["h", "e", "l", "l", "o"]
'тест'.chars      # => ["т", "е", "с", "т"]
'こんにちは'.chars # => ["こ", "ん", "に", "ち", "は"]
static VALUE
rb_str_chars(VALUE str)
{
    VALUE ary = WANTARRAY("chars", rb_str_strlen(str));
    return rb_str_enumerate_chars(str, ary);
}
chomp(line_sep = $/) → new_string 点击切换源代码

返回从 self 复制的新字符串,其中可能删除了尾随字符。

line_sep"\n" 时,如果最后的一个或两个字符是 "\r""\n""\r\n"(但不是 "\n\r"),则删除它们。

$/                    # => "\n"
"abc\r".chomp         # => "abc"
"abc\n".chomp         # => "abc"
"abc\r\n".chomp       # => "abc"
"abc\n\r".chomp       # => "abc\n"
"тест\r\n".chomp      # => "тест"
"こんにちは\r\n".chomp  # => "こんにちは"

line_sep'' (空字符串)时,删除多个尾随的 "\n""\r\n"(但不是 "\r""\n\r")。

"abc\n\n\n".chomp('')           # => "abc"
"abc\r\n\r\n\r\n".chomp('')     # => "abc"
"abc\n\n\r\n\r\n\n\n".chomp('') # => "abc"
"abc\n\r\n\r\n\r".chomp('')     # => "abc\n\r\n\r\n\r"
"abc\r\r\r".chomp('')           # => "abc\r\r\r"

line_sep 既不是 "\n" 也不是 '' 时,如果存在单个尾随行分隔符,则删除它。

'abcd'.chomp('d')  # => "abc"
'abcdd'.chomp('d') # => "abcd"
static VALUE
rb_str_chomp(int argc, VALUE *argv, VALUE str)
{
    VALUE rs = chomp_rs(argc, argv);
    if (NIL_P(rs)) return str_duplicate(rb_cString, str);
    return rb_str_subseq(str, 0, chompped_length(str, rs));
}
chomp!(line_sep = $/) → self 或 nil 点击切换源代码

String#chomp 类似,但在适当位置修改 self;如果未进行任何修改,则返回 nil,否则返回 self

static VALUE
rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
{
    VALUE rs;
    str_modifiable(str);
    if (RSTRING_LEN(str) == 0 && argc < 2) return Qnil;
    rs = chomp_rs(argc, argv);
    if (NIL_P(rs)) return Qnil;
    return rb_str_chomp_string(str, rs);
}
chop → new_string 点击切换源代码

返回一个从 self 复制的新字符串,并可能移除尾随字符。

如果最后两个字符是 "\r\n",则移除它们。

"abc\r\n".chop      # => "abc"
"тест\r\n".chop     # => "тест"
"こんにちは\r\n".chop # => "こんにちは"

否则,如果存在最后一个字符,则移除它。

'abcd'.chop     # => "abc"
'тест'.chop     # => "тес"
'こんにちは'.chop # => "こんにち"
''.chop         # => ""

如果您只需要移除字符串末尾的换行符,String#chomp 是更好的选择。

static VALUE
rb_str_chop(VALUE str)
{
    return rb_str_subseq(str, 0, chopped_length(str));
}
chop! → self or nil 点击切换源代码

String#chop 类似,但会就地修改 self;如果 self 为空,则返回 nil,否则返回 self

相关:String#chomp!

static VALUE
rb_str_chop_bang(VALUE str)
{
    str_modify_keep_cr(str);
    if (RSTRING_LEN(str) > 0) {
        long len;
        len = chopped_length(str);
        STR_SET_LEN(str, len);
        TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
        if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
            ENC_CODERANGE_CLEAR(str);
        }
        return str;
    }
    return Qnil;
}
chr → string 点击切换源代码

返回一个包含 self 的第一个字符的字符串。

s = 'foo' # => "foo"
s.chr     # => "f"
static VALUE
rb_str_chr(VALUE str)
{
    return rb_str_substr(str, 0, 1);
}
clear → self 点击切换源代码

移除 self 的内容。

s = 'foo' # => "foo"
s.clear   # => ""
static VALUE
rb_str_clear(VALUE str)
{
    str_discard(str);
    STR_SET_EMBED(str);
    STR_SET_LEN(str, 0);
    RSTRING_PTR(str)[0] = 0;
    if (rb_enc_asciicompat(STR_ENC_GET(str)))
        ENC_CODERANGE_SET(str, ENC_CODERANGE_7BIT);
    else
        ENC_CODERANGE_SET(str, ENC_CODERANGE_VALID);
    return str;
}
codepoints → array_of_integers 点击切换源代码

返回一个包含 self 中码位的数组;每个码位都是一个字符的整数值。

'hello'.codepoints     # => [104, 101, 108, 108, 111]
'тест'.codepoints      # => [1090, 1077, 1089, 1090]
'こんにちは'.codepoints # => [12371, 12435, 12395, 12385, 12399]
static VALUE
rb_str_codepoints(VALUE str)
{
    VALUE ary = WANTARRAY("codepoints", rb_str_strlen(str));
    return rb_str_enumerate_codepoints(str, ary);
}
concat(*objects) → string 点击切换源代码

objects 中的每个对象连接到 self 并返回 self

s = 'foo'
s.concat('bar', 'baz') # => "foobarbaz"
s                      # => "foobarbaz"

对于每个给定的对象 object,如果它是一个 Integer,则该值被视为码位,并在连接之前转换为字符。

s = 'foo'
s.concat(32, 'bar', 32, 'baz') # => "foo bar baz"

相关:String#<<,它接受单个参数。

static VALUE
rb_str_concat_multi(int argc, VALUE *argv, VALUE str)
{
    str_modifiable(str);

    if (argc == 1) {
        return rb_str_concat(str, argv[0]);
    }
    else if (argc > 1) {
        int i;
        VALUE arg_str = rb_str_tmp_new(0);
        rb_enc_copy(arg_str, str);
        for (i = 0; i < argc; i++) {
            rb_str_concat(arg_str, argv[i]);
        }
        rb_str_buf_append(str, arg_str);
    }

    return str;
}
count(*selectors) → integer 点击切换源代码

返回 self 中由给定的 selectors 指定的字符总数(请参阅多个字符选择器)。

a = "hello world"
a.count "lo"                   #=> 5
a.count "lo", "o"              #=> 2
a.count "hello", "^l"          #=> 4
a.count "ej-m"                 #=> 4

"hello^world".count "\\^aeiou" #=> 4
"hello-world".count "a\\-eo"   #=> 4

c = "hello world\\r\\n"
c.count "\\"                   #=> 2
c.count "\\A"                  #=> 0
c.count "X-\\w"                #=> 3
static VALUE
rb_str_count(int argc, VALUE *argv, VALUE str)
{
    char table[TR_TABLE_SIZE];
    rb_encoding *enc = 0;
    VALUE del = 0, nodel = 0, tstr;
    char *s, *send;
    int i;
    int ascompat;
    size_t n = 0;

    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);

    tstr = argv[0];
    StringValue(tstr);
    enc = rb_enc_check(str, tstr);
    if (argc == 1) {
        const char *ptstr;
        if (RSTRING_LEN(tstr) == 1 && rb_enc_asciicompat(enc) &&
            (ptstr = RSTRING_PTR(tstr),
             ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc, (const unsigned char *)ptstr, (const unsigned char *)ptstr+1)) &&
            !is_broken_string(str)) {
            int clen;
            unsigned char c = rb_enc_codepoint_len(ptstr, ptstr+1, &clen, enc);

            s = RSTRING_PTR(str);
            if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
            send = RSTRING_END(str);
            while (s < send) {
                if (*(unsigned char*)s++ == c) n++;
            }
            return SIZET2NUM(n);
        }
    }

    tr_setup_table(tstr, table, TRUE, &del, &nodel, enc);
    for (i=1; i<argc; i++) {
        tstr = argv[i];
        StringValue(tstr);
        enc = rb_enc_check(str, tstr);
        tr_setup_table(tstr, table, FALSE, &del, &nodel, enc);
    }

    s = RSTRING_PTR(str);
    if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0);
    send = RSTRING_END(str);
    ascompat = rb_enc_asciicompat(enc);
    while (s < send) {
        unsigned int c;

        if (ascompat && (c = *(unsigned char*)s) < 0x80) {
            if (table[c]) {
                n++;
            }
            s++;
        }
        else {
            int clen;
            c = rb_enc_codepoint_len(s, send, &clen, enc);
            if (tr_find(c, table, del, nodel)) {
                n++;
            }
            s += clen;
        }
    }

    return SIZET2NUM(n);
}
crypt(salt_str) → new_string 点击切换源代码

返回通过调用 crypt(3) 标准库函数生成的字符串,该函数以 strsalt_str(按此顺序)作为其参数。请不要再使用此方法。它已过时;仅为了与早期 Ruby 脚本向后兼容而提供。在当代程序中使用它有几个原因是不好的。

  • C 的 crypt(3) 的行为取决于它运行的操作系统。生成的字符串缺乏数据可移植性。

  • 在某些操作系统(如 Mac OS)上,crypt(3) 永远不会失败(即,静默地以意想不到的结果结束)。

  • 在某些操作系统(如 Mac OS)上,crypt(3) 不是线程安全的。

  • 所谓的 crypt(3) 的“传统”用法非常非常弱。根据其手册页,Linux 的传统 crypt(3) 输出只有 2**56 种变体;今天太容易暴力破解了。这是默认行为。

  • 为了使事情更加健壮,一些操作系统实现了所谓的“模块化”用法。要完成此操作,您必须手动复杂地构建 salt_str 参数。生成不正确的盐字符串往往不会产生任何错误;参数中的拼写错误通常是无法检测到的。

    • 例如,在以下示例中,第二次调用 String#crypt 是错误的;“round=” 中存在拼写错误(缺少 “s”)。但是,该调用不会失败,并且会生成一些意想不到的结果。

      "foo".crypt("$5$rounds=1000$salt$") # OK, proper usage
      "foo".crypt("$5$round=1000$salt$")  # Typo not detected
      
  • 即使在“模块化”模式下,某些哈希函数也被认为是过时的,不再推荐使用;例如,模块 $1$ 已被其作者正式放弃:请参阅 phk.freebsd.dk/sagas/md5crypt_eol/。另一个例子,模块 $3$ 被认为已完全损坏:请参阅 FreeBSD 的手册页。

  • 在某些操作系统(如 Mac OS)上,没有模块化模式。但是,如上所述,Mac OS 上的 crypt(3) 永远不会失败。这意味着即使您构建了一个正确的盐字符串,它仍然会生成传统的 DES 哈希,并且您无法意识到这一点。

    "foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
    

如果由于某种原因您无法迁移到其他安全的当代密码哈希算法,请安装 string-crypt gem 并 require 'string/crypt' 以继续使用它。

static VALUE
rb_str_crypt(VALUE str, VALUE salt)
{
#ifdef HAVE_CRYPT_R
    VALUE databuf;
    struct crypt_data *data;
#   define CRYPT_END() ALLOCV_END(databuf)
#else
    extern char *crypt(const char *, const char *);
#   define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
#endif
    VALUE result;
    const char *s, *saltp;
    char *res;
#ifdef BROKEN_CRYPT
    char salt_8bit_clean[3];
#endif

    StringValue(salt);
    mustnot_wchar(str);
    mustnot_wchar(salt);
    s = StringValueCStr(str);
    saltp = RSTRING_PTR(salt);
    if (RSTRING_LEN(salt) < 2 || !saltp[0] || !saltp[1]) {
        rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
    }

#ifdef BROKEN_CRYPT
    if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) {
        salt_8bit_clean[0] = saltp[0] & 0x7f;
        salt_8bit_clean[1] = saltp[1] & 0x7f;
        salt_8bit_clean[2] = '\0';
        saltp = salt_8bit_clean;
    }
#endif
#ifdef HAVE_CRYPT_R
    data = ALLOCV(databuf, sizeof(struct crypt_data));
# ifdef HAVE_STRUCT_CRYPT_DATA_INITIALIZED
    data->initialized = 0;
# endif
    res = crypt_r(s, saltp, data);
#else
    crypt_mutex_initialize();
    rb_nativethread_lock_lock(&crypt_mutex.lock);
    res = crypt(s, saltp);
#endif
    if (!res) {
        int err = errno;
        CRYPT_END();
        rb_syserr_fail(err, "crypt");
    }
    result = rb_str_new_cstr(res);
    CRYPT_END();
    return result;
}
-string → frozen_string
dedup → frozen_string

返回字符串的冻结的、可能预先存在的副本。

只要返回的 String 没有在其上设置任何实例变量并且不是 String 子类,就会对其进行重复数据删除。

请注意,-string 变体更方便用于定义常量

FILENAME = -'config/database.yml'

dedup 更适合在计算链中使用该方法

@url_list.concat(urls.map(&:dedup))
别名:-@
delete(*selectors) → new_string 点击切换源代码

返回 self 的副本,其中删除了由 selectors 指定的字符(请参阅多个字符选择器)。

"hello".delete "l","lo"        #=> "heo"
"hello".delete "lo"            #=> "he"
"hello".delete "aeiou", "^e"   #=> "hell"
"hello".delete "ej-m"          #=> "ho"
static VALUE
rb_str_delete(int argc, VALUE *argv, VALUE str)
{
    str = str_duplicate(rb_cString, str);
    rb_str_delete_bang(argc, argv, str);
    return str;
}
delete!(*selectors) → self or nil 点击切换源代码

String#delete 类似,但会就地修改 self。如果有任何更改,则返回 self,否则返回 nil

static VALUE
rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
{
    char squeez[TR_TABLE_SIZE];
    rb_encoding *enc = 0;
    char *s, *send, *t;
    VALUE del = 0, nodel = 0;
    int modify = 0;
    int i, ascompat, cr;

    if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil;
    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
    for (i=0; i<argc; i++) {
        VALUE s = argv[i];

        StringValue(s);
        enc = rb_enc_check(str, s);
        tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
    }

    str_modify_keep_cr(str);
    ascompat = rb_enc_asciicompat(enc);
    s = t = RSTRING_PTR(str);
    send = RSTRING_END(str);
    cr = ascompat ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
    while (s < send) {
        unsigned int c;
        int clen;

        if (ascompat && (c = *(unsigned char*)s) < 0x80) {
            if (squeez[c]) {
                modify = 1;
            }
            else {
                if (t != s) *t = c;
                t++;
            }
            s++;
        }
        else {
            c = rb_enc_codepoint_len(s, send, &clen, enc);

            if (tr_find(c, squeez, del, nodel)) {
                modify = 1;
            }
            else {
                if (t != s) rb_enc_mbcput(c, t, enc);
                t += clen;
                if (cr == ENC_CODERANGE_7BIT) cr = ENC_CODERANGE_VALID;
            }
            s += clen;
        }
    }
    TERM_FILL(t, TERM_LEN(str));
    STR_SET_LEN(str, t - RSTRING_PTR(str));
    ENC_CODERANGE_SET(str, cr);

    if (modify) return str;
    return Qnil;
}
delete_prefix(prefix) → new_string 点击切换源代码

返回 self 的副本,其中删除了前导子字符串 prefix

'hello'.delete_prefix('hel')      # => "lo"
'hello'.delete_prefix('llo')      # => "hello"
'тест'.delete_prefix('те')        # => "ст"
'こんにちは'.delete_prefix('こん')  # => "にちは"

相关:String#delete_prefix!String#delete_suffix

static VALUE
rb_str_delete_prefix(VALUE str, VALUE prefix)
{
    long prefixlen;

    prefixlen = deleted_prefix_length(str, prefix);
    if (prefixlen <= 0) return str_duplicate(rb_cString, str);

    return rb_str_subseq(str, prefixlen, RSTRING_LEN(str) - prefixlen);
}
delete_prefix!(prefix) → self or nil 点击切换源代码

String#delete_prefix 类似,不同之处在于 self 是就地修改的。如果删除了前缀,则返回 self,否则返回 nil

static VALUE
rb_str_delete_prefix_bang(VALUE str, VALUE prefix)
{
    long prefixlen;
    str_modify_keep_cr(str);

    prefixlen = deleted_prefix_length(str, prefix);
    if (prefixlen <= 0) return Qnil;

    return rb_str_drop_bytes(str, prefixlen);
}
delete_suffix(suffix) → new_string 点击切换源代码

返回 self 的副本,其中删除了尾随子字符串 suffix

'hello'.delete_suffix('llo')      # => "he"
'hello'.delete_suffix('hel')      # => "hello"
'тест'.delete_suffix('ст')        # => "те"
'こんにちは'.delete_suffix('ちは')  # => "こんに"

相关:String#delete_suffix!String#delete_prefix

static VALUE
rb_str_delete_suffix(VALUE str, VALUE suffix)
{
    long suffixlen;

    suffixlen = deleted_suffix_length(str, suffix);
    if (suffixlen <= 0) return str_duplicate(rb_cString, str);

    return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen);
}
delete_suffix!(suffix) → self or nil 点击切换源代码

String#delete_suffix 类似,不同之处在于 self 是就地修改的。如果删除了后缀,则返回 self,否则返回 nil

static VALUE
rb_str_delete_suffix_bang(VALUE str, VALUE suffix)
{
    long olen, suffixlen, len;
    str_modifiable(str);

    suffixlen = deleted_suffix_length(str, suffix);
    if (suffixlen <= 0) return Qnil;

    olen = RSTRING_LEN(str);
    str_modify_keep_cr(str);
    len = olen - suffixlen;
    STR_SET_LEN(str, len);
    TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
    if (ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
        ENC_CODERANGE_CLEAR(str);
    }
    return str;
}
downcase(*options) → string 点击切换源代码

返回一个包含 self 中小写字符的字符串。

s = 'Hello World!' # => "Hello World!"
s.downcase         # => "hello world!"

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关:String#downcase!String#upcaseString#upcase!

static VALUE
rb_str_downcase(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;
    VALUE ret;

    flags = check_case_options(argc, argv, flags);
    enc = str_true_enc(str);
    if (case_option_single_p(flags, enc, str)) {
        ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
        str_enc_copy_direct(ret, str);
        downcase_single(ret);
    }
    else if (flags&ONIGENC_CASE_ASCII_ONLY) {
        ret = rb_str_new(0, RSTRING_LEN(str));
        rb_str_ascii_casemap(str, ret, &flags, enc);
    }
    else {
        ret = rb_str_casemap(str, &flags, enc);
    }

    return ret;
}
downcase!(*options) → self or nil 点击切换源代码

self 中的字符转换为小写;如果有任何更改,则返回 self,否则返回 nil

s = 'Hello World!' # => "Hello World!"
s.downcase!        # => "hello world!"
s                  # => "hello world!"
s.downcase!        # => nil

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关:String#downcaseString#upcaseString#upcase!

static VALUE
rb_str_downcase_bang(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_DOWNCASE;

    flags = check_case_options(argc, argv, flags);
    str_modify_keep_cr(str);
    enc = str_true_enc(str);
    if (case_option_single_p(flags, enc, str)) {
        if (downcase_single(str))
            flags |= ONIGENC_CASE_MODIFIED;
    }
    else if (flags&ONIGENC_CASE_ASCII_ONLY)
        rb_str_ascii_casemap(str, str, &flags, enc);
    else
        str_shared_replace(str, rb_str_casemap(str, &flags, enc));

    if (ONIGENC_CASE_MODIFIED&flags) return str;
    return Qnil;
}
dump → string 点击切换源代码

返回 self 的可打印版本,用双引号括起来,特殊字符转义,非打印字符替换为十六进制表示法。

"hello \n ''".dump    # => "\"hello \\n ''\""
"\f\x00\xff\\\"".dump # => "\"\\f\\x00\\xFF\\\\\\\"\""

相关:String#undumpString#dump 的反向操作)。

VALUE
rb_str_dump(VALUE str)
{
    int encidx = rb_enc_get_index(str);
    rb_encoding *enc = rb_enc_from_index(encidx);
    long len;
    const char *p, *pend;
    char *q, *qend;
    VALUE result;
    int u8 = (encidx == rb_utf8_encindex());
    static const char nonascii_suffix[] = ".dup.force_encoding(\"%s\")";

    len = 2;                    /* "" */
    if (!rb_enc_asciicompat(enc)) {
        len += strlen(nonascii_suffix) - rb_strlen_lit("%s");
        len += strlen(enc->name);
    }

    p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
    while (p < pend) {
        int clen;
        unsigned char c = *p++;

        switch (c) {
          case '"':  case '\\':
          case '\n': case '\r':
          case '\t': case '\f':
          case '\013': case '\010': case '\007': case '\033':
            clen = 2;
            break;

          case '#':
            clen = IS_EVSTR(p, pend) ? 2 : 1;
            break;

          default:
            if (ISPRINT(c)) {
                clen = 1;
            }
            else {
                if (u8 && c > 0x7F) {   /* \u notation */
                    int n = rb_enc_precise_mbclen(p-1, pend, enc);
                    if (MBCLEN_CHARFOUND_P(n)) {
                        unsigned int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
                        if (cc <= 0xFFFF)
                            clen = 6;  /* \uXXXX */
                        else if (cc <= 0xFFFFF)
                            clen = 9;  /* \u{XXXXX} */
                        else
                            clen = 10; /* \u{XXXXXX} */
                        p += MBCLEN_CHARFOUND_LEN(n)-1;
                        break;
                    }
                }
                clen = 4;       /* \xNN */
            }
            break;
        }

        if (clen > LONG_MAX - len) {
            rb_raise(rb_eRuntimeError, "string size too big");
        }
        len += clen;
    }

    result = rb_str_new(0, len);
    p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
    q = RSTRING_PTR(result); qend = q + len + 1;

    *q++ = '"';
    while (p < pend) {
        unsigned char c = *p++;

        if (c == '"' || c == '\\') {
            *q++ = '\\';
            *q++ = c;
        }
        else if (c == '#') {
            if (IS_EVSTR(p, pend)) *q++ = '\\';
            *q++ = '#';
        }
        else if (c == '\n') {
            *q++ = '\\';
            *q++ = 'n';
        }
        else if (c == '\r') {
            *q++ = '\\';
            *q++ = 'r';
        }
        else if (c == '\t') {
            *q++ = '\\';
            *q++ = 't';
        }
        else if (c == '\f') {
            *q++ = '\\';
            *q++ = 'f';
        }
        else if (c == '\013') {
            *q++ = '\\';
            *q++ = 'v';
        }
        else if (c == '\010') {
            *q++ = '\\';
            *q++ = 'b';
        }
        else if (c == '\007') {
            *q++ = '\\';
            *q++ = 'a';
        }
        else if (c == '\033') {
            *q++ = '\\';
            *q++ = 'e';
        }
        else if (ISPRINT(c)) {
            *q++ = c;
        }
        else {
            *q++ = '\\';
            if (u8) {
                int n = rb_enc_precise_mbclen(p-1, pend, enc) - 1;
                if (MBCLEN_CHARFOUND_P(n)) {
                    int cc = rb_enc_mbc_to_codepoint(p-1, pend, enc);
                    p += n;
                    if (cc <= 0xFFFF)
                        snprintf(q, qend-q, "u%04X", cc);    /* \uXXXX */
                    else
                        snprintf(q, qend-q, "u{%X}", cc);  /* \u{XXXXX} or \u{XXXXXX} */
                    q += strlen(q);
                    continue;
                }
            }
            snprintf(q, qend-q, "x%02X", c);
            q += 3;
        }
    }
    *q++ = '"';
    *q = '\0';
    if (!rb_enc_asciicompat(enc)) {
        snprintf(q, qend-q, nonascii_suffix, enc->name);
        encidx = rb_ascii8bit_encindex();
    }
    /* result from dump is ASCII */
    rb_enc_associate_index(result, encidx);
    ENC_CODERANGE_SET(result, ENC_CODERANGE_7BIT);
    return result;
}
each_byte {|byte| ... } → self 点击切换源代码
each_byte → enumerator

使用 self 中的每个连续字节调用给定的块;返回 self

'hello'.each_byte {|byte| print byte, ' ' }
print "\n"
'тест'.each_byte {|byte| print byte, ' ' }
print "\n"
'こんにちは'.each_byte {|byte| print byte, ' ' }
print "\n"

输出

104 101 108 108 111
209 130 208 181 209 129 209 130
227 129 147 227 130 147 227 129 171 227 129 161 227 129 175

如果未给出块,则返回枚举器。

static VALUE
rb_str_each_byte(VALUE str)
{
    RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_byte_size);
    return rb_str_enumerate_bytes(str, 0);
}
each_char {|c| ... } → self 点击切换源代码
each_char → enumerator

使用 self 中的每个连续字符调用给定的块;返回 self

'hello'.each_char {|char| print char, ' ' }
print "\n"
'тест'.each_char {|char| print char, ' ' }
print "\n"
'こんにちは'.each_char {|char| print char, ' ' }
print "\n"

输出

h e l l o
т е с т
    

如果未给出块,则返回枚举器。

static VALUE
rb_str_each_char(VALUE str)
{
    RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
    return rb_str_enumerate_chars(str, 0);
}
each_codepoint {|integer| ... } → self 点击切换源代码
each_codepoint → enumerator

使用 self 中的每个连续码位调用给定的块;每个码位都是一个字符的整数值;返回 self

'hello'.each_codepoint {|codepoint| print codepoint, ' ' }
print "\n"
'тест'.each_codepoint {|codepoint| print codepoint, ' ' }
print "\n"
'こんにちは'.each_codepoint {|codepoint| print codepoint, ' ' }
print "\n"

输出

104 101 108 108 111
1090 1077 1089 1090
12371 12435 12395 12385 12399

如果未给出块,则返回枚举器。

static VALUE
rb_str_each_codepoint(VALUE str)
{
    RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_char_size);
    return rb_str_enumerate_codepoints(str, 0);
}
each_grapheme_cluster {|gc| ... } → self 点击切换源代码
each_grapheme_cluster → enumerator

使用 self 中的每个连续字素簇调用给定的块(请参阅Unicode 字素簇边界);返回 self

s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈"
s.each_grapheme_cluster {|gc| print gc, ' ' }

输出

ä - p q r - b̈ - x y z - c̈

如果未给出块,则返回枚举器。

static VALUE
rb_str_each_grapheme_cluster(VALUE str)
{
    RETURN_SIZED_ENUMERATOR(str, 0, 0, rb_str_each_grapheme_cluster_size);
    return rb_str_enumerate_grapheme_clusters(str, 0);
}
each_line(line_sep = $/, chomp: false) {|substring| ... } → self 点击切换源代码
each_line(line_sep = $/, chomp: false) → enumerator

给定一个块,形成子字符串(“行”),这些子字符串是通过在 self 的每次出现给定的行分隔符 line_sep 处分割 self 而产生的;将每一行传递给该块;返回 self

s = <<~EOT
This is the first line.
This is line two.

This is line four.
This is line five.
EOT

s.each_line {|line| p line }

输出

"This is the first line.\n"
"This is line two.\n"
"\n"
"This is line four.\n"
"This is line five.\n"

使用不同的 line_sep

s.each_line(' is ') {|line| p line }

输出

"This is "
"the first line.\nThis is "
"line two.\n\nThis is "
"line four.\nThis is "
"line five.\n"

如果 chomptrue,则从每一行中删除尾随的 line_sep

s.each_line(chomp: true) {|line| p line }

输出

"This is the first line."
"This is line two."
""
"This is line four."
"This is line five."

如果 line_sep 为空字符串,则通过在每次出现两个或多个换行符时进行分割,形成并传递“段落”。

s.each_line('') {|line| p line }

输出

"This is the first line.\nThis is line two.\n\n"
"This is line four.\nThis is line five.\n"

如果没有给出块,则返回一个枚举器。

static VALUE
rb_str_each_line(int argc, VALUE *argv, VALUE str)
{
    RETURN_SIZED_ENUMERATOR(str, argc, argv, 0);
    return rb_str_enumerate_lines(argc, argv, str, 0);
}
empty? → true or false 点击切换源代码

如果 self 的长度为零,则返回 true,否则返回 false

"hello".empty? # => false
" ".empty? # => false
"".empty? # => true
static VALUE
rb_str_empty(VALUE str)
{
    return RBOOL(RSTRING_LEN(str) == 0);
}
encode(dst_encoding = Encoding.default_internal, **enc_opts) → string 点击切换源代码
encode(dst_encoding, src_encoding, **enc_opts) → string

返回一个 self 的副本,该副本已按照 dst_encoding 确定的方式进行转码。默认情况下,如果 self 包含无效字节或 dst_encoding 中未定义的字符,则会引发异常;可以通过编码选项修改该行为;请参见下文。

没有参数。

  • 如果 Encoding.default_internalnil(默认值),则使用相同的编码。

    Encoding.default_internal # => nil
    s = "Ruby\x99".force_encoding('Windows-1252')
    s.encoding                # => #<Encoding:Windows-1252>
    s.bytes                   # => [82, 117, 98, 121, 153]
    t = s.encode              # => "Ruby\x99"
    t.encoding                # => #<Encoding:Windows-1252>
    t.bytes                   # => [82, 117, 98, 121, 226, 132, 162]
    
  • 否则,使用编码 Encoding.default_internal

    Encoding.default_internal = 'UTF-8'
    t = s.encode              # => "Ruby™"
    t.encoding                # => #<Encoding:UTF-8>
    

如果仅给定参数 dst_encoding,则使用该编码。

s = "Ruby\x99".force_encoding('Windows-1252')
s.encoding            # => #<Encoding:Windows-1252>
t = s.encode('UTF-8') # => "Ruby™"
t.encoding            # => #<Encoding:UTF-8>

如果给定参数 dst_encodingsrc_encoding,则使用 src_encoding 解释 self,并使用 dst_encoding 编码新字符串。

s = "Ruby\x99"
t = s.encode('UTF-8', 'Windows-1252') # => "Ruby™"
t.encoding                            # => #<Encoding:UTF-8>

可选关键字参数 enc_opts 指定编码选项;请参阅编码选项

请注意,除非给定 invalid: :replace 选项,否则从编码 enc 转换为相同的编码 enc(无论 enc 是显式还是隐式给定)都是无操作的,即该字符串只是简单地复制,没有任何更改,即使存在无效字节也不会引发任何异常。

static VALUE
str_encode(int argc, VALUE *argv, VALUE str)
{
    VALUE newstr = str;
    int encidx = str_transcode(argc, argv, &newstr);
    return encoded_dup(newstr, str, encidx);
}
encode!(dst_encoding = Encoding.default_internal, **enc_opts) → self 点击切换源代码
encode!(dst_encoding, src_encoding, **enc_opts) → self

encode 类似,但将编码更改应用于 self;返回 self

static VALUE
str_encode_bang(int argc, VALUE *argv, VALUE str)
{
    VALUE newstr;
    int encidx;

    rb_check_frozen(str);

    newstr = str;
    encidx = str_transcode(argc, argv, &newstr);

    if (encidx < 0) return str;
    if (newstr == str) {
        rb_enc_associate_index(str, encidx);
        return str;
    }
    rb_str_shared_replace(str, newstr);
    return str_encode_associate(str, encidx);
}
encoding → encoding 点击切换源代码

返回一个 Encoding 对象,该对象表示 obj 的编码。

VALUE
rb_obj_encoding(VALUE obj)
{
    int idx = rb_enc_get_index(obj);
    if (idx < 0) {
        rb_raise(rb_eTypeError, "unknown encoding");
    }
    return rb_enc_from_encoding_index(idx & ENC_INDEX_MASK);
}
end_with?(*strings) → true 或 false 点击切换源代码

返回 self 是否以任何给定的 strings 结尾。

如果任何给定的字符串与结尾匹配,则返回 true,否则返回 false

'hello'.end_with?('ello')               #=> true
'hello'.end_with?('heaven', 'ello')     #=> true
'hello'.end_with?('heaven', 'paradise') #=> false
'тест'.end_with?('т')                   # => true
'こんにちは'.end_with?('は')              # => true

相关方法:String#start_with?

static VALUE
rb_str_end_with(int argc, VALUE *argv, VALUE str)
{
    int i;

    for (i=0; i<argc; i++) {
        VALUE tmp = argv[i];
        const char *p, *s, *e;
        long slen, tlen;
        rb_encoding *enc;

        StringValue(tmp);
        enc = rb_enc_check(str, tmp);
        if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
        if ((slen = RSTRING_LEN(str)) < tlen) continue;
        p = RSTRING_PTR(str);
        e = p + slen;
        s = e - tlen;
        if (!at_char_boundary(p, s, e, enc))
            continue;
        if (memcmp(s, RSTRING_PTR(tmp), tlen) == 0)
            return Qtrue;
    }
    return Qfalse;
}
eql?(object) → true 或 false 点击切换源代码

如果 object 具有与 self 相同的长度和内容,则返回 true;否则返回 false

s = 'foo'
s.eql?('foo') # => true
s.eql?('food') # => false
s.eql?('FOO') # => false

如果两个字符串的编码不兼容,则返回 false

"\u{e4 f6 fc}".encode("ISO-8859-1").eql?("\u{c4 d6 dc}") # => false
VALUE
rb_str_eql(VALUE str1, VALUE str2)
{
    if (str1 == str2) return Qtrue;
    if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;
    return rb_str_eql_internal(str1, str2);
}
force_encoding(encoding) → self 点击切换源代码

self 的编码更改为 encoding,它可以是字符串编码名称或 Encoding 对象;返回 self。

s = 'łał'
s.bytes                   # => [197, 130, 97, 197, 130]
s.encoding                # => #<Encoding:UTF-8>
s.force_encoding('ascii') # => "\xC5\x82a\xC5\x82"
s.encoding                # => #<Encoding:US-ASCII>

不会更改底层字节。

s.bytes                   # => [197, 130, 97, 197, 130]

即使给定的 encodingself 无效(如上面的更改),也会进行更改。

s.valid_encoding?                 # => false
s.force_encoding(Encoding::UTF_8) # => "łał"
s.valid_encoding?                 # => true
static VALUE
rb_str_force_encoding(VALUE str, VALUE enc)
{
    str_modifiable(str);

    rb_encoding *encoding = rb_to_encoding(enc);
    int idx = rb_enc_to_index(encoding);

    // If the encoding is unchanged, we do nothing.
    if (ENCODING_GET(str) == idx) {
        return str;
    }

    rb_enc_associate_index(str, idx);

    // If the coderange was 7bit and the new encoding is ASCII-compatible
    // we can keep the coderange.
    if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT && encoding && rb_enc_asciicompat(encoding)) {
        return str;
    }

    ENC_CODERANGE_CLEAR(str);
    return str;
}
getbyte(index) → integer 或 nil 点击切换源代码

返回基于零的 index 处的字节作为整数,如果 index 超出范围,则返回 nil

s = 'abcde'   # => "abcde"
s.getbyte(0)  # => 97
s.getbyte(-1) # => 101
s.getbyte(5)  # => nil

相关方法:String#setbyte

VALUE
rb_str_getbyte(VALUE str, VALUE index)
{
    long pos = NUM2LONG(index);

    if (pos < 0)
        pos += RSTRING_LEN(str);
    if (pos < 0 ||  RSTRING_LEN(str) <= pos)
        return Qnil;

    return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
}
grapheme_clusters → array_of_grapheme_clusters 点击切换源代码

返回 self 中字形簇的数组(请参阅 Unicode 字形簇边界)。

s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈"
s.grapheme_clusters
# => ["ä", "-", "p", "q", "r", "-", "b̈", "-", "x", "y", "z", "-", "c̈"]
static VALUE
rb_str_grapheme_clusters(VALUE str)
{
    VALUE ary = WANTARRAY("grapheme_clusters", rb_str_strlen(str));
    return rb_str_enumerate_grapheme_clusters(str, ary);
}
gsub(pattern, replacement) → new_string 点击切换源代码
gsub(pattern) {|match| ... } → new_string
gsub(pattern) → enumerator

返回 self 的副本,其中所有出现的给定 pattern 都被替换。

请参阅 替换方法

如果没有给出 replacement 且没有给出块,则返回一个 Enumerator

相关方法:String#subString#sub!String#gsub!

static VALUE
rb_str_gsub(int argc, VALUE *argv, VALUE str)
{
    return str_gsub(argc, argv, str, 0);
}
gsub!(pattern, replacement) → self 或 nil 点击切换源代码
gsub!(pattern) {|match| ... } → self 或 nil
gsub!(pattern) → an_enumerator

self 上执行指定的子字符串替换;如果发生任何替换,则返回 self,否则返回 nil

请参阅 替换方法

如果没有给出 replacement 且没有给出块,则返回一个 Enumerator

相关方法:String#subString#gsubString#sub!

static VALUE
rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
{
    str_modify_keep_cr(str);
    return str_gsub(argc, argv, str, 1);
}
hash → integer 点击切换源代码

返回 self 的整数哈希值。该值基于 self 的长度、内容和编码。

相关方法:Object#hash

static VALUE
rb_str_hash_m(VALUE str)
{
    st_index_t hval = rb_str_hash(str);
    return ST2FIX(hval);
}
hex → integer 点击切换源代码

self 的前导子字符串解释为十六进制数字字符串(带有可选的符号和可选的 0x),并返回相应的数字;如果没有这样的前导子字符串,则返回零。

'0x0a'.hex        # => 10
'-1234'.hex       # => -4660
'0'.hex           # => 0
'non-numeric'.hex # => 0

相关方法:String#oct

static VALUE
rb_str_hex(VALUE str)
{
    return rb_str_to_inum(str, 16, FALSE);
}
include?(other_string) → true 或 false 点击切换源代码

如果 self 包含 other_string,则返回 true,否则返回 false

s = 'foo'
s.include?('f')    # => true
s.include?('fo')   # => true
s.include?('food') # => false
VALUE
rb_str_include(VALUE str, VALUE arg)
{
    long i;

    StringValue(arg);
    i = rb_str_index(str, arg, 0);

    return RBOOL(i != -1);
}
index(substring, offset = 0) → integer 或 nil 点击切换源代码
index(regexp, offset = 0) → integer 或 nil

返回给定参数的第一个匹配项的整数索引,如果没有找到,则返回 nil;对 self 的搜索是向前的,并从位置 offset(以字符为单位)开始。

使用字符串参数 substring,返回 self 中第一个匹配子字符串的索引。

'foo'.index('f')         # => 0
'foo'.index('o')         # => 1
'foo'.index('oo')        # => 1
'foo'.index('ooo')       # => nil
'тест'.index('с')        # => 2
'こんにちは'.index('ち')   # => 3

使用 Regexp 参数 regexp,返回 self 中第一个匹配项的索引。

'foo'.index(/o./) # => 1
'foo'.index(/.o/) # => 0

使用正整数 offset,从位置 offset 开始搜索。

'foo'.index('o', 1)        # => 1
'foo'.index('o', 2)        # => 2
'foo'.index('o', 3)        # => nil
'тест'.index('с', 1)       # => 2
'こんにちは'.index('ち', 2)  # => 3

使用负整数 offset,通过从 self 的末尾向后计数来选择搜索位置。

'foo'.index('o', -1)  # => 2
'foo'.index('o', -2)  # => 1
'foo'.index('o', -3)  # => 1
'foo'.index('o', -4)  # => nil
'foo'.index(/o./, -2) # => 1
'foo'.index(/.o/, -2) # => 1

相关方法:String#rindex

static VALUE
rb_str_index_m(int argc, VALUE *argv, VALUE str)
{
    VALUE sub;
    VALUE initpos;
    rb_encoding *enc = STR_ENC_GET(str);
    long pos;

    if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
        long slen = str_strlen(str, enc); /* str's enc */
        pos = NUM2LONG(initpos);
        if (pos < 0 ? (pos += slen) < 0 : pos > slen) {
            if (RB_TYPE_P(sub, T_REGEXP)) {
                rb_backref_set(Qnil);
            }
            return Qnil;
        }
    }
    else {
        pos = 0;
    }

    if (RB_TYPE_P(sub, T_REGEXP)) {
        pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
                         enc, single_byte_optimizable(str));

        if (rb_reg_search(sub, str, pos, 0) >= 0) {
            VALUE match = rb_backref_get();
            struct re_registers *regs = RMATCH_REGS(match);
            pos = rb_str_sublen(str, BEG(0));
            return LONG2NUM(pos);
        }
    }
    else {
        StringValue(sub);
        pos = rb_str_index(str, sub, pos);
        if (pos >= 0) {
            pos = rb_str_sublen(str, pos);
            return LONG2NUM(pos);
        }
    }
    return Qnil;
}
initialize_copy(other_string) -> self 点击切换源代码

other_string 的内容替换 self 的内容。

s = 'foo'        # => "foo"
s.replace('bar') # => "bar"
VALUE
rb_str_replace(VALUE str, VALUE str2)
{
    str_modifiable(str);
    if (str == str2) return str;

    StringValue(str2);
    str_discard(str);
    return str_replace(str, str2);
}
也别名为:replace
insert(index, other_string) → self 点击切换源代码

将给定的 other_string 插入到 self 中;返回 self

如果 Integer index 为正数,则在偏移量 index 处插入 other_string

'foo'.insert(1, 'bar') # => "fbaroo"

如果 Integer index 为负数,则从 self 的末尾向后计数,并在偏移量 index+1 处插入 other_string(即在 self[index] 之后)。

'foo'.insert(-2, 'bar') # => "fobaro"
static VALUE
rb_str_insert(VALUE str, VALUE idx, VALUE str2)
{
    long pos = NUM2LONG(idx);

    if (pos == -1) {
        return rb_str_append(str, str2);
    }
    else if (pos < 0) {
        pos++;
    }
    rb_str_update(str, pos, 0, str2);
    return str;
}
inspect → string 点击切换源代码

返回 self 的可打印版本,用双引号括起来,并转义特殊字符。

s = "foo\tbar\tbaz\n"
s.inspect
# => "\"foo\\tbar\\tbaz\\n\""
VALUE
rb_str_inspect(VALUE str)
{
    int encidx = ENCODING_GET(str);
    rb_encoding *enc = rb_enc_from_index(encidx);
    const char *p, *pend, *prev;
    char buf[CHAR_ESC_LEN + 1];
    VALUE result = rb_str_buf_new(0);
    rb_encoding *resenc = rb_default_internal_encoding();
    int unicode_p = rb_enc_unicode_p(enc);
    int asciicompat = rb_enc_asciicompat(enc);

    if (resenc == NULL) resenc = rb_default_external_encoding();
    if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();
    rb_enc_associate(result, resenc);
    str_buf_cat2(result, "\"");

    p = RSTRING_PTR(str); pend = RSTRING_END(str);
    prev = p;
    while (p < pend) {
        unsigned int c, cc;
        int n;

        n = rb_enc_precise_mbclen(p, pend, enc);
        if (!MBCLEN_CHARFOUND_P(n)) {
            if (p > prev) str_buf_cat(result, prev, p - prev);
            n = rb_enc_mbminlen(enc);
            if (pend < p + n)
                n = (int)(pend - p);
            while (n--) {
                snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
                str_buf_cat(result, buf, strlen(buf));
                prev = ++p;
            }
            continue;
        }
        n = MBCLEN_CHARFOUND_LEN(n);
        c = rb_enc_mbc_to_codepoint(p, pend, enc);
        p += n;
        if ((asciicompat || unicode_p) &&
          (c == '"'|| c == '\\' ||
            (c == '#' &&
             p < pend &&
             MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
             (cc = rb_enc_codepoint(p,pend,enc),
              (cc == '$' || cc == '@' || cc == '{'))))) {
            if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
            str_buf_cat2(result, "\\");
            if (asciicompat || enc == resenc) {
                prev = p - n;
                continue;
            }
        }
        switch (c) {
          case '\n': cc = 'n'; break;
          case '\r': cc = 'r'; break;
          case '\t': cc = 't'; break;
          case '\f': cc = 'f'; break;
          case '\013': cc = 'v'; break;
          case '\010': cc = 'b'; break;
          case '\007': cc = 'a'; break;
          case 033: cc = 'e'; break;
          default: cc = 0; break;
        }
        if (cc) {
            if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
            buf[0] = '\\';
            buf[1] = (char)cc;
            str_buf_cat(result, buf, 2);
            prev = p;
            continue;
        }
        /* The special casing of 0x85 (NEXT_LINE) here is because
         * Oniguruma historically treats it as printable, but it
         * doesn't match the print POSIX bracket class or character
         * property in regexps.
         *
         * See Ruby Bug #16842 for details:
         * https://bugs.ruby-lang.org/issues/16842
         */
        if ((enc == resenc && rb_enc_isprint(c, enc) && c != 0x85) ||
            (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c))) {
            continue;
        }
        else {
            if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
            rb_str_buf_cat_escaped_char(result, c, unicode_p);
            prev = p;
            continue;
        }
    }
    if (p > prev) str_buf_cat(result, prev, p - prev);
    str_buf_cat2(result, "\"");

    return result;
}
intern → symbol 点击切换源代码

返回与 str 相对应的 Symbol,如果该符号以前不存在,则创建该符号。请参阅 Symbol#id2name

"Koala".intern         #=> :Koala
s = 'cat'.to_sym       #=> :cat
s == :cat              #=> true
s = '@cat'.to_sym      #=> :@cat
s == :@cat             #=> true

这也可用于创建不能使用 :xxx 表示法表示的符号。

'cat and dog'.to_sym   #=> :"cat and dog"
VALUE
rb_str_intern(VALUE str)
{
    VALUE sym;

    GLOBAL_SYMBOLS_ENTER(symbols);
    {
        sym = lookup_str_sym_with_lock(symbols, str);

        if (sym) {
            // ok
        }
        else if (USE_SYMBOL_GC) {
            rb_encoding *enc = rb_enc_get(str);
            rb_encoding *ascii = rb_usascii_encoding();
            if (enc != ascii && sym_check_asciionly(str, false)) {
                str = rb_str_dup(str);
                rb_enc_associate(str, ascii);
                OBJ_FREEZE(str);
                enc = ascii;
            }
            else {
                str = rb_str_dup(str);
                OBJ_FREEZE(str);
            }
            str = rb_fstring(str);
            int type = rb_str_symname_type(str, IDSET_ATTRSET_FOR_INTERN);
            if (type < 0) type = ID_JUNK;
            sym = dsymbol_alloc(symbols, rb_cSymbol, str, enc, type);
        }
        else {
            ID id = intern_str(str, 0);
            sym = ID2SYM(id);
        }
    }
    GLOBAL_SYMBOLS_LEAVE();
    return sym;
}
也别名为:to_sym
length → integer 点击切换源代码

返回 self 中字符(非字节)的计数。

'foo'.length        # => 3
'тест'.length       # => 4
'こんにちは'.length   # => 5

String#bytesize 对比。

'foo'.bytesize        # => 3
'тест'.bytesize       # => 8
'こんにちは'.bytesize   # => 15
VALUE
rb_str_length(VALUE str)
{
    return LONG2NUM(str_strlen(str, NULL));
}
也别名为:size
lines(Line_sep = $/, chomp: false) → array_of_strings 点击切换源代码

根据给定的参数形成 self 的子字符串(“行”)(有关详细信息,请参阅 String#each_line);返回数组中的行。

static VALUE
rb_str_lines(int argc, VALUE *argv, VALUE str)
{
    VALUE ary = WANTARRAY("lines", 0);
    return rb_str_enumerate_lines(argc, argv, str, ary);
}
ljust(size, pad_string = ' ') → new_string 点击切换源代码

返回 self 的左对齐副本。

如果整数参数 size 大于 self 的大小(以字符为单位),则返回长度为 size 的新字符串,该字符串是 self 的副本,左对齐并在右侧用 pad_string 填充。

'hello'.ljust(10)       # => "hello     "
'  hello'.ljust(10)     # => "  hello   "
'hello'.ljust(10, 'ab') # => "helloababa"
'тест'.ljust(10)        # => "тест      "
'こんにちは'.ljust(10)    # => "こんにちは     "

如果 size 不大于 self 的大小,则返回 self 的副本。

'hello'.ljust(5)  # => "hello"
'hello'.ljust(1)  # => "hello"

相关方法:String#rjustString#center

static VALUE
rb_str_ljust(int argc, VALUE *argv, VALUE str)
{
    return rb_str_justify(argc, argv, str, 'l');
}
lstrip → new_string 点击切换源代码

返回删除了前导空格的 self 的副本;请参阅 字符串中的空格

whitespace = "\x00\t\n\v\f\r "
s = whitespace + 'abc' + whitespace
s        # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
s.lstrip # => "abc\u0000\t\n\v\f\r "

相关方法:String#rstripString#strip

static VALUE
rb_str_lstrip(VALUE str)
{
    char *start;
    long len, loffset;
    RSTRING_GETMEM(str, start, len);
    loffset = lstrip_offset(str, start, start+len, STR_ENC_GET(str));
    if (loffset <= 0) return str_duplicate(rb_cString, str);
    return rb_str_subseq(str, loffset, len - loffset);
}
lstrip! → self 或 nil 点击切换源代码

类似于 String#lstrip,只是任何修改都在 self 中进行;如果进行了任何修改,则返回 self,否则返回 nil

相关方法:String#rstrip!String#strip!

static VALUE
rb_str_lstrip_bang(VALUE str)
{
    rb_encoding *enc;
    char *start, *s;
    long olen, loffset;

    str_modify_keep_cr(str);
    enc = STR_ENC_GET(str);
    RSTRING_GETMEM(str, start, olen);
    loffset = lstrip_offset(str, start, start+olen, enc);
    if (loffset > 0) {
        long len = olen-loffset;
        s = start + loffset;
        memmove(start, s, len);
        STR_SET_LEN(str, len);
        TERM_FILL(start+len, rb_enc_mbminlen(enc));
        return str;
    }
    return Qnil;
}
match(pattern, offset = 0) → matchdata 或 nil 点击切换源代码
match(pattern, offset = 0) {|matchdata| ... } → object

基于 self 和给定的 pattern 返回一个 MatchData 对象(或 nil)。

注意:还会更新 Regexp 的全局变量

  • 通过转换 pattern(如果还不是 Regexp)来计算 regexp

    regexp = Regexp.new(pattern)
    
  • 计算 matchdata,它将是一个 MatchData 对象或 nil(请参阅 Regexp#match)。

    matchdata = <tt>regexp.match(self)

如果未给出块,则返回计算出的 matchdata

'foo'.match('f') # => #<MatchData "f">
'foo'.match('o') # => #<MatchData "o">
'foo'.match('x') # => nil

如果给出了 Integer 参数 offset,则搜索从索引 offset 开始。

'foo'.match('f', 1) # => nil
'foo'.match('o', 1) # => #<MatchData "o">

如果给出了块,则使用计算出的 matchdata 调用该块,并返回该块的返回值。

'foo'.match(/o/) {|matchdata| matchdata } # => #<MatchData "o">
'foo'.match(/x/) {|matchdata| matchdata } # => nil
'foo'.match(/f/, 1) {|matchdata| matchdata } # => nil
static VALUE
rb_str_match_m(int argc, VALUE *argv, VALUE str)
{
    VALUE re, result;
    if (argc < 1)
        rb_check_arity(argc, 1, 2);
    re = argv[0];
    argv[0] = str;
    result = rb_funcallv(get_pat(re), rb_intern("match"), argc, argv);
    if (!NIL_P(result) && rb_block_given_p()) {
        return rb_yield(result);
    }
    return result;
}
match?(pattern, offset = 0) → true 或 false 点击切换源代码

基于是否找到 selfpattern 的匹配项返回 truefalse

注意:不会更新 Regexp 的全局变量

通过转换 pattern(如果还不是 Regexp)来计算 regexp

regexp = Regexp.new(pattern)

如果 self+.match(regexp) 返回一个 MatchData 对象,则返回 true,否则返回 false

'foo'.match?(/o/) # => true
'foo'.match?('o') # => true
'foo'.match?(/x/) # => false

如果给出了 Integer 参数 offset,则搜索从索引 offset 开始。

'foo'.match?('f', 1) # => false
'foo'.match?('o', 1) # => true
static VALUE
rb_str_match_m_p(int argc, VALUE *argv, VALUE str)
{
    VALUE re;
    rb_check_arity(argc, 1, 2);
    re = get_pat(argv[0]);
    return rb_reg_match_p(re, str, argc > 1 ? NUM2LONG(argv[1]) : 0);
}
next()

返回 self 的后继。后继是通过递增字符计算的。

要递增的第一个字符是最右边的字母数字字符:或者,如果没有字母数字字符,则是最右边的字符。

'THX1138'.succ # => "THX1139"
'<<koala>>'.succ # => "<<koalb>>"
'***'.succ # => '**+'

数字的后继是另一个数字,从 9 到 0 的“翻转”情况下,将“进位”到左边的下一个字符,并在必要时添加另一个数字。

'00'.succ # => "01"
'09'.succ # => "10"
'99'.succ # => "100"

字母的后继是同一大小写的另一个字母,在翻转的情况下,将进位到左边的下一个字符,并在必要时添加另一个相同大小写的字母。

'aa'.succ # => "ab"
'az'.succ # => "ba"
'zz'.succ # => "aaa"
'AA'.succ # => "AB"
'AZ'.succ # => "BA"
'ZZ'.succ # => "AAA"

非字母数字字符的后继是底层字符集排序序列中的下一个字符,在翻转的情况下,将进位到左边的下一个字符,并在必要时添加另一个字符。

s = 0.chr * 3
s # => "\x00\x00\x00"
s.succ # => "\x00\x00\x01"
s = 255.chr * 3
s # => "\xFF\xFF\xFF"
s.succ # => "\x01\x00\x00\x00"

进位可以在字母数字字符的混合之间发生。

s = 'zz99zz99'
s.succ # => "aaa00aa00"
s = '99zz99zz'
s.succ # => "100aa00aa"

String 的后继是一个新的空 String

''.succ # => ""
别名为:succ
next!()

等效于 String#succ,但在原地修改 self;返回 self

别名为:succ!
oct → integer 点击切换源代码

self 的前导子字符串解释为八进制数字字符串(带有可选符号),并返回对应的数字;如果不存在这样的前导子字符串,则返回零。

'123'.oct             # => 83
'-377'.oct            # => -255
'0377non-numeric'.oct # => 255
'non-numeric'.oct     # => 0

如果 self0 开头,则会遵循基数指示符;请参阅 Kernel#Integer

相关方法:String#hex

static VALUE
rb_str_oct(VALUE str)
{
    return rb_str_to_inum(str, -8, FALSE);
}
ord → integer 点击切换源代码

返回 self 的第一个字符的整数序号。

'h'.ord         # => 104
'hello'.ord     # => 104
'тест'.ord      # => 1090
'こんにちは'.ord  # => 12371
static VALUE
rb_str_ord(VALUE s)
{
    unsigned int c;

    c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
    return UINT2NUM(c);
}
partition(string_or_regexp) → [head, match, tail] 点击切换源代码

返回 self 的 3 个元素的子字符串数组。

从头开始扫描,将模式与 self 进行匹配。 模式是:

  • 如果 string_or_regexpRegexp 本身,则使用它。

  • 如果 string_or_regexp 是字符串,则使用 Regexp.quote(string_or_regexp)

如果模式匹配,则返回匹配前字符串、第一个匹配字符串和匹配后字符串。

'hello'.partition('l')      # => ["he", "l", "lo"]
'hello'.partition('ll')     # => ["he", "ll", "o"]
'hello'.partition('h')      # => ["", "h", "ello"]
'hello'.partition('o')      # => ["hell", "o", ""]
'hello'.partition(/l+/)     #=> ["he", "ll", "o"]
'hello'.partition('')       # => ["", "", "hello"]
'тест'.partition('т')       # => ["", "т", "ест"]
'こんにちは'.partition('に')  # => ["こん", "に", "ちは"]

如果模式不匹配,则返回 self 的副本和两个空字符串。

'hello'.partition('x') # => ["hello", "", ""]

相关方法:String#rpartitionString#split

static VALUE
rb_str_partition(VALUE str, VALUE sep)
{
    long pos;

    sep = get_pat_quoted(sep, 0);
    if (RB_TYPE_P(sep, T_REGEXP)) {
        if (rb_reg_search(sep, str, 0, 0) < 0) {
            goto failed;
        }
        VALUE match = rb_backref_get();
        struct re_registers *regs = RMATCH_REGS(match);

        pos = BEG(0);
        sep = rb_str_subseq(str, pos, END(0) - pos);
    }
    else {
        pos = rb_str_index(str, sep, 0);
        if (pos < 0) goto failed;
    }
    return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
                          sep,
                          rb_str_subseq(str, pos+RSTRING_LEN(sep),
                                             RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));

  failed:
    return rb_ary_new3(3, str_duplicate(rb_cString, str), str_new_empty_String(str), str_new_empty_String(str));
}
prepend(*other_strings) → string 点击切换源代码

other_strings 中的每个字符串添加到 self 的开头,并返回 self

s = 'foo'
s.prepend('bar', 'baz') # => "barbazfoo"
s                       # => "barbazfoo"

相关方法:String#concat

static VALUE
rb_str_prepend_multi(int argc, VALUE *argv, VALUE str)
{
    str_modifiable(str);

    if (argc == 1) {
        rb_str_update(str, 0L, 0L, argv[0]);
    }
    else if (argc > 1) {
        int i;
        VALUE arg_str = rb_str_tmp_new(0);
        rb_enc_copy(arg_str, str);
        for (i = 0; i < argc; i++) {
            rb_str_append(arg_str, argv[i]);
        }
        rb_str_update(str, 0L, 0L, arg_str);
    }

    return str;
}
replace(other_string) → self

other_string 的内容替换 self 的内容。

s = 'foo'        # => "foo"
s.replace('bar') # => "bar"
reverse → string 点击切换源代码

返回一个新字符串,其中包含 self 中的字符,但顺序相反。

'stressed'.reverse # => "desserts"
static VALUE
rb_str_reverse(VALUE str)
{
    rb_encoding *enc;
    VALUE rev;
    char *s, *e, *p;
    int cr;

    if (RSTRING_LEN(str) <= 1) return str_duplicate(rb_cString, str);
    enc = STR_ENC_GET(str);
    rev = rb_str_new(0, RSTRING_LEN(str));
    s = RSTRING_PTR(str); e = RSTRING_END(str);
    p = RSTRING_END(rev);
    cr = ENC_CODERANGE(str);

    if (RSTRING_LEN(str) > 1) {
        if (single_byte_optimizable(str)) {
            while (s < e) {
                *--p = *s++;
            }
        }
        else if (cr == ENC_CODERANGE_VALID) {
            while (s < e) {
                int clen = rb_enc_fast_mbclen(s, e, enc);

                p -= clen;
                memcpy(p, s, clen);
                s += clen;
            }
        }
        else {
            cr = rb_enc_asciicompat(enc) ?
                ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
            while (s < e) {
                int clen = rb_enc_mbclen(s, e, enc);

                if (clen > 1 || (*s & 0x80)) cr = ENC_CODERANGE_UNKNOWN;
                p -= clen;
                memcpy(p, s, clen);
                s += clen;
            }
        }
    }
    STR_SET_LEN(rev, RSTRING_LEN(str));
    str_enc_copy_direct(rev, str);
    ENC_CODERANGE_SET(rev, cr);

    return rev;
}
reverse! → self 点击切换源代码

返回字符顺序颠倒的 self

s = 'stressed'
s.reverse! # => "desserts"
s          # => "desserts"
static VALUE
rb_str_reverse_bang(VALUE str)
{
    if (RSTRING_LEN(str) > 1) {
        if (single_byte_optimizable(str)) {
            char *s, *e, c;

            str_modify_keep_cr(str);
            s = RSTRING_PTR(str);
            e = RSTRING_END(str) - 1;
            while (s < e) {
                c = *s;
                *s++ = *e;
                *e-- = c;
            }
        }
        else {
            str_shared_replace(str, rb_str_reverse(str));
        }
    }
    else {
        str_modify_keep_cr(str);
    }
    return str;
}
rindex(substring, offset = self.length) → integer or nil 点击切换源代码
rindex(regexp, offset = self.length) → integer or nil

返回给定的 substring *最后*一次出现的 Integer 索引,如果未找到,则返回 nil

'foo'.rindex('f') # => 0
'foo'.rindex('o') # => 2
'foo'.rindex('oo') # => 1
'foo'.rindex('ooo') # => nil

返回给定的 Regexp regexp *最后*一次匹配的 Integer 索引,如果未找到,则返回 nil

'foo'.rindex(/f/) # => 0
'foo'.rindex(/o/) # => 2
'foo'.rindex(/oo/) # => 1
'foo'.rindex(/ooo/) # => nil

_最后_ 一次匹配是指从可能的最后位置开始,而不是最长的匹配项的最后一次。

'foo'.rindex(/o+/) # => 2
$~ #=> #<MatchData "o">

要获得最长的最后一次匹配,需要与负向后查找结合使用。

'foo'.rindex(/(?<!o)o+/) # => 1
$~ #=> #<MatchData "oo">

或者使用带有负向先行断言的 String#index

'foo'.index(/o+(?!.*o)/) # => 1
$~ #=> #<MatchData "oo">

如果给定 Integer 参数 offset 且为非负数,则指定字符串中搜索的*结束*最大起始位置。

'foo'.rindex('o', 0) # => nil
'foo'.rindex('o', 1) # => 1
'foo'.rindex('o', 2) # => 2
'foo'.rindex('o', 3) # => 2

如果 offset 是一个负数 Integer,则字符串中 _结束_ 搜索的最大起始位置是字符串的长度与 offset 的和。

'foo'.rindex('o', -1) # => 2
'foo'.rindex('o', -2) # => 1
'foo'.rindex('o', -3) # => nil
'foo'.rindex('o', -4) # => nil

相关方法:String#index

static VALUE
rb_str_rindex_m(int argc, VALUE *argv, VALUE str)
{
    VALUE sub;
    VALUE initpos;
    rb_encoding *enc = STR_ENC_GET(str);
    long pos, len = str_strlen(str, enc); /* str's enc */

    if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
        pos = NUM2LONG(initpos);
        if (pos < 0 && (pos += len) < 0) {
            if (RB_TYPE_P(sub, T_REGEXP)) {
                rb_backref_set(Qnil);
            }
            return Qnil;
        }
        if (pos > len) pos = len;
    }
    else {
        pos = len;
    }

    if (RB_TYPE_P(sub, T_REGEXP)) {
        /* enc = rb_enc_check(str, sub); */
        pos = str_offset(RSTRING_PTR(str), RSTRING_END(str), pos,
                         enc, single_byte_optimizable(str));

        if (rb_reg_search(sub, str, pos, 1) >= 0) {
            VALUE match = rb_backref_get();
            struct re_registers *regs = RMATCH_REGS(match);
            pos = rb_str_sublen(str, BEG(0));
            return LONG2NUM(pos);
        }
    }
    else {
        StringValue(sub);
        pos = rb_str_rindex(str, sub, pos);
        if (pos >= 0) {
            pos = rb_str_sublen(str, pos);
            return LONG2NUM(pos);
        }
    }
    return Qnil;
}
rjust(size, pad_string = ' ') → new_string 点击切换源代码

返回一个右对齐的 self 副本。

如果整数参数 size 大于 self 的大小(以字符为单位),则返回一个长度为 size 的新字符串,它是 self 的副本,右对齐并在左侧用 pad_string 填充。

'hello'.rjust(10)       # => "     hello"
'hello  '.rjust(10)     # => "   hello  "
'hello'.rjust(10, 'ab') # => "ababahello"
'тест'.rjust(10)        # => "      тест"
'こんにちは'.rjust(10)    # => "     こんにちは"

如果 size 不大于 self 的大小,则返回 self 的副本。

'hello'.rjust(5, 'ab')  # => "hello"
'hello'.rjust(1, 'ab')  # => "hello"

相关方法:String#ljustString#center

static VALUE
rb_str_rjust(int argc, VALUE *argv, VALUE str)
{
    return rb_str_justify(argc, argv, str, 'r');
}
rpartition(sep) → [head, match, tail] 点击切换源代码

返回 self 的 3 个元素的子字符串数组。

从末尾向后扫描,将模式与 self 进行匹配。模式是:

  • 如果 string_or_regexpRegexp 本身,则使用它。

  • 如果 string_or_regexp 是字符串,则使用 Regexp.quote(string_or_regexp)

如果模式匹配,则返回匹配前字符串、最后一次匹配字符串和匹配后字符串。

'hello'.rpartition('l')      # => ["hel", "l", "o"]
'hello'.rpartition('ll')     # => ["he", "ll", "o"]
'hello'.rpartition('h')      # => ["", "h", "ello"]
'hello'.rpartition('o')      # => ["hell", "o", ""]
'hello'.rpartition(/l+/)     # => ["hel", "l", "o"]
'hello'.rpartition('')       # => ["hello", "", ""]
'тест'.rpartition('т')       # => ["тес", "т", ""]
'こんにちは'.rpartition('に')  # => ["こん", "に", "ちは"]

如果模式不匹配,则返回两个空字符串和 self 的副本。

'hello'.rpartition('x') # => ["", "", "hello"]

相关方法:String#partitionString#split

static VALUE
rb_str_rpartition(VALUE str, VALUE sep)
{
    long pos = RSTRING_LEN(str);

    sep = get_pat_quoted(sep, 0);
    if (RB_TYPE_P(sep, T_REGEXP)) {
        if (rb_reg_search(sep, str, pos, 1) < 0) {
            goto failed;
        }
        VALUE match = rb_backref_get();
        struct re_registers *regs = RMATCH_REGS(match);

        pos = BEG(0);
        sep = rb_str_subseq(str, pos, END(0) - pos);
    }
    else {
        pos = rb_str_sublen(str, pos);
        pos = rb_str_rindex(str, sep, pos);
        if (pos < 0) {
            goto failed;
        }
    }

    return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
                          sep,
                          rb_str_subseq(str, pos+RSTRING_LEN(sep),
                                        RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
  failed:
    return rb_ary_new3(3, str_new_empty_String(str), str_new_empty_String(str), str_duplicate(rb_cString, str));
}
rstrip → new_string 点击切换源代码

返回接收器的副本,其中删除了尾随空格;请参阅 字符串中的空格

whitespace = "\x00\t\n\v\f\r "
s = whitespace + 'abc' + whitespace
s        # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
s.rstrip # => "\u0000\t\n\v\f\r abc"

相关方法:String#lstripString#strip

static VALUE
rb_str_rstrip(VALUE str)
{
    rb_encoding *enc;
    char *start;
    long olen, roffset;

    enc = STR_ENC_GET(str);
    RSTRING_GETMEM(str, start, olen);
    roffset = rstrip_offset(str, start, start+olen, enc);

    if (roffset <= 0) return str_duplicate(rb_cString, str);
    return rb_str_subseq(str, 0, olen-roffset);
}
rstrip! → self or nil 点击切换源代码

String#rstrip 类似,但所有修改都在 self 中进行;如果进行了任何修改,则返回 self,否则返回 nil

相关方法:String#lstrip!String#strip!

static VALUE
rb_str_rstrip_bang(VALUE str)
{
    rb_encoding *enc;
    char *start;
    long olen, roffset;

    str_modify_keep_cr(str);
    enc = STR_ENC_GET(str);
    RSTRING_GETMEM(str, start, olen);
    roffset = rstrip_offset(str, start, start+olen, enc);
    if (roffset > 0) {
        long len = olen - roffset;

        STR_SET_LEN(str, len);
        TERM_FILL(start+len, rb_enc_mbminlen(enc));
        return str;
    }
    return Qnil;
}
scan(string_or_regexp) → array 点击切换源代码
scan(string_or_regexp) {|matches| ... } → self

将模式与 self 进行匹配;模式是:

  • 如果 string_or_regexpRegexp 本身,则使用它。

  • 如果 string_or_regexp 是字符串,则使用 Regexp.quote(string_or_regexp)

遍历 self,生成匹配结果的集合。

  • 如果模式不包含任何组,则每个结果都是匹配的字符串 $&

  • 如果模式包含组,则每个结果都是一个数组,其中包含每个组的一个条目。

如果没有给出块,则返回结果数组。

s = 'cruel world'
s.scan(/\w+/)      # => ["cruel", "world"]
s.scan(/.../)      # => ["cru", "el ", "wor"]
s.scan(/(...)/)    # => [["cru"], ["el "], ["wor"]]
s.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]]

如果给出了块,则使用每个结果调用该块;返回 self

s.scan(/\w+/) {|w| print "<<#{w}>> " }
print "\n"
s.scan(/(.)(.)/) {|x,y| print y, x }
print "\n"

输出

<<cruel>> <<world>>
rceu lowlr
static VALUE
rb_str_scan(VALUE str, VALUE pat)
{
    VALUE result;
    long start = 0;
    long last = -1, prev = 0;
    char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);

    pat = get_pat_quoted(pat, 1);
    mustnot_broken(str);
    if (!rb_block_given_p()) {
        VALUE ary = rb_ary_new();

        while (!NIL_P(result = scan_once(str, pat, &start, 0))) {
            last = prev;
            prev = start;
            rb_ary_push(ary, result);
        }
        if (last >= 0) rb_pat_search(pat, str, last, 1);
        else rb_backref_set(Qnil);
        return ary;
    }

    while (!NIL_P(result = scan_once(str, pat, &start, 1))) {
        last = prev;
        prev = start;
        rb_yield(result);
        str_mod_check(str, p, len);
    }
    if (last >= 0) rb_pat_search(pat, str, last, 1);
    return str;
}
scrub(replacement_string = default_replacement) → new_string 点击切换源代码
scrub{|bytes| ... } → new_string

返回 self 的副本,其中每个无效的字节序列都被给定的 replacement_string 替换。

如果没有给出块且没有给出参数,则将每个无效序列替换为默认的替换字符串(对于 Unicode 编码为 "�",否则为 '?')。

s = "foo\x81\x81bar"
s.scrub # => "foo��bar"

如果没有给出块且给出了参数 replacement_string,则将每个无效序列替换为该字符串。

"foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar"

如果给出了块,则将每个无效序列替换为块的值。

"foo\x81\x81bar".scrub {|bytes| p bytes; 'XYZZY' }
# => "fooXYZZYXYZZYbar"

输出

"\x81"
"\x81"
static VALUE
str_scrub(int argc, VALUE *argv, VALUE str)
{
    VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
    VALUE new = rb_str_scrub(str, repl);
    return NIL_P(new) ? str_duplicate(rb_cString, str): new;
}
scrub! → self 点击切换源代码
scrub!(replacement_string = default_replacement) → self
scrub!{|bytes| ... } → self

String#scrub 类似,但所有替换都在 self 中进行。

static VALUE
str_scrub_bang(int argc, VALUE *argv, VALUE str)
{
    VALUE repl = argc ? (rb_check_arity(argc, 0, 1), argv[0]) : Qnil;
    VALUE new = rb_str_scrub(str, repl);
    if (!NIL_P(new)) rb_str_replace(str, new);
    return str;
}
setbyte(index, integer) → integer 点击切换源代码

将从零开始的 index 处的字节设置为 integer;返回 integer

s = 'abcde'      # => "abcde"
s.setbyte(0, 98) # => 98
s                # => "bbcde"

相关方法:String#getbyte

VALUE
rb_str_setbyte(VALUE str, VALUE index, VALUE value)
{
    long pos = NUM2LONG(index);
    long len = RSTRING_LEN(str);
    char *ptr, *head, *left = 0;
    rb_encoding *enc;
    int cr = ENC_CODERANGE_UNKNOWN, width, nlen;

    if (pos < -len || len <= pos)
        rb_raise(rb_eIndexError, "index %ld out of string", pos);
    if (pos < 0)
        pos += len;

    VALUE v = rb_to_int(value);
    VALUE w = rb_int_and(v, INT2FIX(0xff));
    char byte = (char)(NUM2INT(w) & 0xFF);

    if (!str_independent(str))
        str_make_independent(str);
    enc = STR_ENC_GET(str);
    head = RSTRING_PTR(str);
    ptr = &head[pos];
    if (!STR_EMBED_P(str)) {
        cr = ENC_CODERANGE(str);
        switch (cr) {
          case ENC_CODERANGE_7BIT:
            left = ptr;
            *ptr = byte;
            if (ISASCII(byte)) goto end;
            nlen = rb_enc_precise_mbclen(left, head+len, enc);
            if (!MBCLEN_CHARFOUND_P(nlen))
                ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
            else
                ENC_CODERANGE_SET(str, ENC_CODERANGE_VALID);
            goto end;
          case ENC_CODERANGE_VALID:
            left = rb_enc_left_char_head(head, ptr, head+len, enc);
            width = rb_enc_precise_mbclen(left, head+len, enc);
            *ptr = byte;
            nlen = rb_enc_precise_mbclen(left, head+len, enc);
            if (!MBCLEN_CHARFOUND_P(nlen))
                ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
            else if (MBCLEN_CHARFOUND_LEN(nlen) != width || ISASCII(byte))
                ENC_CODERANGE_CLEAR(str);
            goto end;
        }
    }
    ENC_CODERANGE_CLEAR(str);
    *ptr = byte;

  end:
    return value;
}
size()

返回 self 中字符(非字节)的计数。

'foo'.length        # => 3
'тест'.length       # => 4
'こんにちは'.length   # => 5

String#bytesize 对比。

'foo'.bytesize        # => 3
'тест'.bytesize       # => 8
'こんにちは'.bytesize   # => 15
别名:length
slice(*args)

返回由参数指定的 self 的子字符串。请参阅 字符串切片中的示例。

别名:[]
slice!(index) → new_string or nil 点击切换源代码
slice!(start, length) → new_string or nil
slice!(range) → new_string or nil
slice!(regexp, capture = 0) → new_string or nil
slice!(substring) → new_string or nil

删除并返回由参数指定的 self 的子字符串。请参阅 字符串切片

一些示例

string = "This is a string"
string.slice!(2)        #=> "i"
string.slice!(3..6)     #=> " is "
string.slice!(/s.*t/)   #=> "sa st"
string.slice!("r")      #=> "r"
string                  #=> "Thing"
static VALUE
rb_str_slice_bang(int argc, VALUE *argv, VALUE str)
{
    VALUE result = Qnil;
    VALUE indx;
    long beg, len = 1;
    char *p;

    rb_check_arity(argc, 1, 2);
    str_modify_keep_cr(str);
    indx = argv[0];
    if (RB_TYPE_P(indx, T_REGEXP)) {
        if (rb_reg_search(indx, str, 0, 0) < 0) return Qnil;
        VALUE match = rb_backref_get();
        struct re_registers *regs = RMATCH_REGS(match);
        int nth = 0;
        if (argc > 1 && (nth = rb_reg_backref_number(match, argv[1])) < 0) {
            if ((nth += regs->num_regs) <= 0) return Qnil;
        }
        else if (nth >= regs->num_regs) return Qnil;
        beg = BEG(nth);
        len = END(nth) - beg;
        goto subseq;
    }
    else if (argc == 2) {
        beg = NUM2LONG(indx);
        len = NUM2LONG(argv[1]);
        goto num_index;
    }
    else if (FIXNUM_P(indx)) {
        beg = FIX2LONG(indx);
        if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
        if (!len) return Qnil;
        beg = p - RSTRING_PTR(str);
        goto subseq;
    }
    else if (RB_TYPE_P(indx, T_STRING)) {
        beg = rb_str_index(str, indx, 0);
        if (beg == -1) return Qnil;
        len = RSTRING_LEN(indx);
        result = str_duplicate(rb_cString, indx);
        goto squash;
    }
    else {
        switch (rb_range_beg_len(indx, &beg, &len, str_strlen(str, NULL), 0)) {
          case Qnil:
            return Qnil;
          case Qfalse:
            beg = NUM2LONG(indx);
            if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
            if (!len) return Qnil;
            beg = p - RSTRING_PTR(str);
            goto subseq;
          default:
            goto num_index;
        }
    }

  num_index:
    if (!(p = rb_str_subpos(str, beg, &len))) return Qnil;
    beg = p - RSTRING_PTR(str);

  subseq:
    result = rb_str_new(RSTRING_PTR(str)+beg, len);
    rb_enc_cr_str_copy_for_substr(result, str);

  squash:
    if (len > 0) {
        if (beg == 0) {
            rb_str_drop_bytes(str, len);
        }
        else {
            char *sptr = RSTRING_PTR(str);
            long slen = RSTRING_LEN(str);
            if (beg + len > slen) /* pathological check */
                len = slen - beg;
            memmove(sptr + beg,
                    sptr + beg + len,
                    slen - (beg + len));
            slen -= len;
            STR_SET_LEN(str, slen);
            TERM_FILL(&sptr[slen], TERM_LEN(str));
        }
    }
    return result;
}
split(field_sep = $;, limit = 0) → array 点击切换源代码
split(field_sep = $;, limit = 0) {|substring| ... } → self

返回 self 的子字符串数组,这些子字符串是在每次出现给定的字段分隔符 field_sep 时分割 self 的结果。

field_sep$; 时:

  • 如果 $;nil (其默认值),则分割的发生就像 field_sep 被给定为空格字符一样(见下文)。

  • 如果 $; 为字符串,则分割的发生就像 field_sep 被给定为该字符串一样(见下文)。

field_sep' 'limit0 (其默认值)时,分割发生在每个空格序列处。

'abc def ghi'.split(' ')         => ["abc", "def", "ghi"]
"abc \n\tdef\t\n  ghi".split(' ') # => ["abc", "def", "ghi"]
'abc  def   ghi'.split(' ')      => ["abc", "def", "ghi"]
''.split(' ')                    => []

field_sep 为与 ' ' 不同的字符串且 limit0 时,分割发生在每次出现 field_sep 时;不返回尾随的空子字符串。

'abracadabra'.split('ab')  => ["", "racad", "ra"]
'aaabcdaaa'.split('a')     => ["", "", "", "bcd"]
''.split('a')              => []
'3.14159'.split('1')       => ["3.", "4", "59"]
'!@#$%^$&*($)_+'.split('$') # => ["!@#", "%^", "&*(", ")_+"]
'тест'.split('т')          => ["", "ес"]
'こんにちは'.split('に')     => ["こん", "ちは"]

field_sepRegexplimit0 时,分割发生在每次匹配时;不返回尾随的空子字符串。

'abracadabra'.split(/ab/) # => ["", "racad", "ra"]
'aaabcdaaa'.split(/a/)   => ["", "", "", "bcd"]
'aaabcdaaa'.split(//)    => ["a", "a", "a", "b", "c", "d", "a", "a", "a"]
'1 + 1 == 2'.split(/\W+/) # => ["1", "1", "2"]

如果正则表达式包含组,则它们的匹配项也包含在返回的数组中。

'1:2:3'.split(/(:)()()/, 2) # => ["1", ":", "", "", "2:3"]

如上所述,如果 limit0,则不返回尾随的空子字符串。

'aaabcdaaa'.split('a')   => ["", "", "", "bcd"]

如果 limit 为正整数 n,则最多发生 n - 1 次分割,因此最多返回 n 个子字符串,并且包含尾随的空子字符串。

'aaabcdaaa'.split('a', 1) # => ["aaabcdaaa"]
'aaabcdaaa'.split('a', 2) # => ["", "aabcdaaa"]
'aaabcdaaa'.split('a', 5) # => ["", "", "", "bcd", "aa"]
'aaabcdaaa'.split('a', 7) # => ["", "", "", "bcd", "", "", ""]
'aaabcdaaa'.split('a', 8) # => ["", "", "", "bcd", "", "", ""]

请注意,如果 field_sep 是包含组的正则表达式,则它们的匹配项位于返回的数组中,但不计入限制。

如果 limit 为负数,则其行为与 limit 为零时相同,这意味着没有限制,并且包含尾随的空子字符串。

'aaabcdaaa'.split('a', -1) # => ["", "", "", "bcd", "", "", ""]

如果给出了块,则使用每个子字符串调用它。

'abc def ghi'.split(' ') {|substring| p substring }

输出

"abc"
"def"
"ghi"

相关方法:String#partitionString#rpartition

static VALUE
rb_str_split_m(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    VALUE spat;
    VALUE limit;
    split_type_t split_type;
    long beg, end, i = 0, empty_count = -1;
    int lim = 0;
    VALUE result, tmp;

    result = rb_block_given_p() ? Qfalse : Qnil;
    if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
        lim = NUM2INT(limit);
        if (lim <= 0) limit = Qnil;
        else if (lim == 1) {
            if (RSTRING_LEN(str) == 0)
                return result ? rb_ary_new2(0) : str;
            tmp = str_duplicate(rb_cString, str);
            if (!result) {
                rb_yield(tmp);
                return str;
            }
            return rb_ary_new3(1, tmp);
        }
        i = 1;
    }
    if (NIL_P(limit) && !lim) empty_count = 0;

    enc = STR_ENC_GET(str);
    split_type = SPLIT_TYPE_REGEXP;
    if (!NIL_P(spat)) {
        spat = get_pat_quoted(spat, 0);
    }
    else if (NIL_P(spat = rb_fs)) {
        split_type = SPLIT_TYPE_AWK;
    }
    else if (!(spat = rb_fs_check(spat))) {
        rb_raise(rb_eTypeError, "value of $; must be String or Regexp");
    }
    else {
        rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$; is set to non-nil value");
    }
    if (split_type != SPLIT_TYPE_AWK) {
        switch (BUILTIN_TYPE(spat)) {
          case T_REGEXP:
            rb_reg_options(spat); /* check if uninitialized */
            tmp = RREGEXP_SRC(spat);
            split_type = literal_split_pattern(tmp, SPLIT_TYPE_REGEXP);
            if (split_type == SPLIT_TYPE_AWK) {
                spat = tmp;
                split_type = SPLIT_TYPE_STRING;
            }
            break;

          case T_STRING:
            mustnot_broken(spat);
            split_type = literal_split_pattern(spat, SPLIT_TYPE_STRING);
            break;

          default:
            UNREACHABLE_RETURN(Qnil);
        }
    }

#define SPLIT_STR(beg, len) (empty_count = split_string(result, str, beg, len, empty_count))

    beg = 0;
    char *ptr = RSTRING_PTR(str);
    char *eptr = RSTRING_END(str);
    if (split_type == SPLIT_TYPE_AWK) {
        char *bptr = ptr;
        int skip = 1;
        unsigned int c;

        if (result) result = rb_ary_new();
        end = beg;
        if (is_ascii_string(str)) {
            while (ptr < eptr) {
                c = (unsigned char)*ptr++;
                if (skip) {
                    if (ascii_isspace(c)) {
                        beg = ptr - bptr;
                    }
                    else {
                        end = ptr - bptr;
                        skip = 0;
                        if (!NIL_P(limit) && lim <= i) break;
                    }
                }
                else if (ascii_isspace(c)) {
                    SPLIT_STR(beg, end-beg);
                    skip = 1;
                    beg = ptr - bptr;
                    if (!NIL_P(limit)) ++i;
                }
                else {
                    end = ptr - bptr;
                }
            }
        }
        else {
            while (ptr < eptr) {
                int n;

                c = rb_enc_codepoint_len(ptr, eptr, &n, enc);
                ptr += n;
                if (skip) {
                    if (rb_isspace(c)) {
                        beg = ptr - bptr;
                    }
                    else {
                        end = ptr - bptr;
                        skip = 0;
                        if (!NIL_P(limit) && lim <= i) break;
                    }
                }
                else if (rb_isspace(c)) {
                    SPLIT_STR(beg, end-beg);
                    skip = 1;
                    beg = ptr - bptr;
                    if (!NIL_P(limit)) ++i;
                }
                else {
                    end = ptr - bptr;
                }
            }
        }
    }
    else if (split_type == SPLIT_TYPE_STRING) {
        char *str_start = ptr;
        char *substr_start = ptr;
        char *sptr = RSTRING_PTR(spat);
        long slen = RSTRING_LEN(spat);

        if (result) result = rb_ary_new();
        mustnot_broken(str);
        enc = rb_enc_check(str, spat);
        while (ptr < eptr &&
               (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) {
            /* Check we are at the start of a char */
            char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc);
            if (t != ptr + end) {
                ptr = t;
                continue;
            }
            SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start);
            ptr += end + slen;
            substr_start = ptr;
            if (!NIL_P(limit) && lim <= ++i) break;
        }
        beg = ptr - str_start;
    }
    else if (split_type == SPLIT_TYPE_CHARS) {
        char *str_start = ptr;
        int n;

        if (result) result = rb_ary_new_capa(RSTRING_LEN(str));
        mustnot_broken(str);
        enc = rb_enc_get(str);
        while (ptr < eptr &&
               (n = rb_enc_precise_mbclen(ptr, eptr, enc)) > 0) {
            SPLIT_STR(ptr - str_start, n);
            ptr += n;
            if (!NIL_P(limit) && lim <= ++i) break;
        }
        beg = ptr - str_start;
    }
    else {
        if (result) result = rb_ary_new();
        long len = RSTRING_LEN(str);
        long start = beg;
        long idx;
        int last_null = 0;
        struct re_registers *regs;
        VALUE match = 0;

        for (; rb_reg_search(spat, str, start, 0) >= 0;
             (match ? (rb_match_unbusy(match), rb_backref_set(match)) : (void)0)) {
            match = rb_backref_get();
            if (!result) rb_match_busy(match);
            regs = RMATCH_REGS(match);
            end = BEG(0);
            if (start == end && BEG(0) == END(0)) {
                if (!ptr) {
                    SPLIT_STR(0, 0);
                    break;
                }
                else if (last_null == 1) {
                    SPLIT_STR(beg, rb_enc_fast_mbclen(ptr+beg, eptr, enc));
                    beg = start;
                }
                else {
                    if (start == len)
                        start++;
                    else
                        start += rb_enc_fast_mbclen(ptr+start,eptr,enc);
                    last_null = 1;
                    continue;
                }
            }
            else {
                SPLIT_STR(beg, end-beg);
                beg = start = END(0);
            }
            last_null = 0;

            for (idx=1; idx < regs->num_regs; idx++) {
                if (BEG(idx) == -1) continue;
                SPLIT_STR(BEG(idx), END(idx)-BEG(idx));
            }
            if (!NIL_P(limit) && lim <= ++i) break;
        }
        if (match) rb_match_unbusy(match);
    }
    if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
        SPLIT_STR(beg, RSTRING_LEN(str)-beg);
    }

    return result ? result : str;
}
squeeze(*selectors) → new_string 点击切换源代码

返回 self 的副本,其中 selectors 指定的字符被“压缩”(请参阅 多个字符选择器)。

“压缩”意味着选定字符的每个多字符运行都被压缩为单个字符;如果没有给出任何参数,则压缩所有字符。

"yellow moon".squeeze                  #=> "yelow mon"
"  now   is  the".squeeze(" ")         #=> " now is the"
"putters shoot balls".squeeze("m-z")   #=> "puters shot balls"
static VALUE
rb_str_squeeze(int argc, VALUE *argv, VALUE str)
{
    str = str_duplicate(rb_cString, str);
    rb_str_squeeze_bang(argc, argv, str);
    return str;
}
squeeze!(*selectors) → self or nil 点击切换源代码

String#squeeze 类似,但就地修改 self。如果进行了任何更改,则返回 self,否则返回 nil

static VALUE
rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
{
    char squeez[TR_TABLE_SIZE];
    rb_encoding *enc = 0;
    VALUE del = 0, nodel = 0;
    unsigned char *s, *send, *t;
    int i, modify = 0;
    int ascompat, singlebyte = single_byte_optimizable(str);
    unsigned int save;

    if (argc == 0) {
        enc = STR_ENC_GET(str);
    }
    else {
        for (i=0; i<argc; i++) {
            VALUE s = argv[i];

            StringValue(s);
            enc = rb_enc_check(str, s);
            if (singlebyte && !single_byte_optimizable(s))
                singlebyte = 0;
            tr_setup_table(s, squeez, i==0, &del, &nodel, enc);
        }
    }

    str_modify_keep_cr(str);
    s = t = (unsigned char *)RSTRING_PTR(str);
    if (!s || RSTRING_LEN(str) == 0) return Qnil;
    send = (unsigned char *)RSTRING_END(str);
    save = -1;
    ascompat = rb_enc_asciicompat(enc);

    if (singlebyte) {
        while (s < send) {
            unsigned int c = *s++;
            if (c != save || (argc > 0 && !squeez[c])) {
                *t++ = save = c;
            }
        }
    }
    else {
        while (s < send) {
            unsigned int c;
            int clen;

            if (ascompat && (c = *s) < 0x80) {
                if (c != save || (argc > 0 && !squeez[c])) {
                    *t++ = save = c;
                }
                s++;
            }
            else {
                c = rb_enc_codepoint_len((char *)s, (char *)send, &clen, enc);

                if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) {
                    if (t != s) rb_enc_mbcput(c, t, enc);
                    save = c;
                    t += clen;
                }
                s += clen;
            }
        }
    }

    TERM_FILL((char *)t, TERM_LEN(str));
    if ((char *)t - RSTRING_PTR(str) != RSTRING_LEN(str)) {
        STR_SET_LEN(str, (char *)t - RSTRING_PTR(str));
        modify = 1;
    }

    if (modify) return str;
    return Qnil;
}
start_with?(*string_or_regexp) → true or false 点击切换源代码

返回 self 是否以任何给定的 string_or_regexp 开头。

将模式与 self 的开头进行匹配。对于每个给定的 string_or_regexp,模式是:

  • 如果 string_or_regexpRegexp 本身,则使用它。

  • 如果 string_or_regexp 是字符串,则使用 Regexp.quote(string_or_regexp)

如果任何模式与开头匹配,则返回 true,否则返回 false

'hello'.start_with?('hell')               # => true
'hello'.start_with?(/H/i)                 # => true
'hello'.start_with?('heaven', 'hell')     # => true
'hello'.start_with?('heaven', 'paradise') # => false
'тест'.start_with?('т')                   # => true
'こんにちは'.start_with?('こ')              # => true

相关方法:String#end_with?

static VALUE
rb_str_start_with(int argc, VALUE *argv, VALUE str)
{
    int i;

    for (i=0; i<argc; i++) {
        VALUE tmp = argv[i];
        if (RB_TYPE_P(tmp, T_REGEXP)) {
            if (rb_reg_start_with_p(tmp, str))
                return Qtrue;
        }
        else {
            const char *p, *s, *e;
            long slen, tlen;
            rb_encoding *enc;

            StringValue(tmp);
            enc = rb_enc_check(str, tmp);
            if ((tlen = RSTRING_LEN(tmp)) == 0) return Qtrue;
            if ((slen = RSTRING_LEN(str)) < tlen) continue;
            p = RSTRING_PTR(str);
            e = p + slen;
            s = p + tlen;
            if (!at_char_right_boundary(p, s, e, enc))
                continue;
            if (memcmp(p, RSTRING_PTR(tmp), tlen) == 0)
                return Qtrue;
        }
    }
    return Qfalse;
}
strip → new_string 点击切换源代码

返回接收器的副本,其中删除了前导和尾随空格;请参阅 字符串中的空格

whitespace = "\x00\t\n\v\f\r "
s = whitespace + 'abc' + whitespace
s       # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r "
s.strip # => "abc"

相关方法:String#lstripString#rstrip

static VALUE
rb_str_strip(VALUE str)
{
    char *start;
    long olen, loffset, roffset;
    rb_encoding *enc = STR_ENC_GET(str);

    RSTRING_GETMEM(str, start, olen);
    loffset = lstrip_offset(str, start, start+olen, enc);
    roffset = rstrip_offset(str, start+loffset, start+olen, enc);

    if (loffset <= 0 && roffset <= 0) return str_duplicate(rb_cString, str);
    return rb_str_subseq(str, loffset, olen-loffset-roffset);
}
strip! → self or nil 点击切换源代码

String#strip 类似,但所有修改都在 self 中进行;如果进行了任何修改,则返回 self,否则返回 nil

相关方法:String#lstrip!String#strip!

static VALUE
rb_str_strip_bang(VALUE str)
{
    char *start;
    long olen, loffset, roffset;
    rb_encoding *enc;

    str_modify_keep_cr(str);
    enc = STR_ENC_GET(str);
    RSTRING_GETMEM(str, start, olen);
    loffset = lstrip_offset(str, start, start+olen, enc);
    roffset = rstrip_offset(str, start+loffset, start+olen, enc);

    if (loffset > 0 || roffset > 0) {
        long len = olen-roffset;
        if (loffset > 0) {
            len -= loffset;
            memmove(start, start + loffset, len);
        }
        STR_SET_LEN(str, len);
        TERM_FILL(start+len, rb_enc_mbminlen(enc));
        return str;
    }
    return Qnil;
}
sub(pattern, replacement) → new_string 点击切换源代码
sub(pattern) {|match| ... } → new_string

返回 self 的副本,其中只替换给定 pattern 的第一次出现(而不是所有出现)。

请参阅 替换方法

相关链接:String#sub!, String#gsub, String#gsub!

static VALUE
rb_str_sub(int argc, VALUE *argv, VALUE str)
{
    str = str_duplicate(rb_cString, str);
    rb_str_sub_bang(argc, argv, str);
    return str;
}
sub!(pattern, replacement) → self or nil 点击切换源代码
sub!(pattern) {|match| ... } → self or nil

替换 self 中给定的 pattern 的第一个匹配项(不是所有匹配项);如果发生了替换,则返回 self,否则返回 nil

请参阅 替换方法

相关链接:String#sub, String#gsub, String#gsub!

static VALUE
rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
{
    VALUE pat, repl, hash = Qnil;
    int iter = 0;
    long plen;
    int min_arity = rb_block_given_p() ? 1 : 2;
    long beg;

    rb_check_arity(argc, min_arity, 2);
    if (argc == 1) {
        iter = 1;
    }
    else {
        repl = argv[1];
        hash = rb_check_hash_type(argv[1]);
        if (NIL_P(hash)) {
            StringValue(repl);
        }
    }

    pat = get_pat_quoted(argv[0], 1);

    str_modifiable(str);
    beg = rb_pat_search(pat, str, 0, 1);
    if (beg >= 0) {
        rb_encoding *enc;
        int cr = ENC_CODERANGE(str);
        long beg0, end0;
        VALUE match, match0 = Qnil;
        struct re_registers *regs;
        char *p, *rp;
        long len, rlen;

        match = rb_backref_get();
        regs = RMATCH_REGS(match);
        if (RB_TYPE_P(pat, T_STRING)) {
            beg0 = beg;
            end0 = beg0 + RSTRING_LEN(pat);
            match0 = pat;
        }
        else {
            beg0 = BEG(0);
            end0 = END(0);
            if (iter) match0 = rb_reg_nth_match(0, match);
        }

        if (iter || !NIL_P(hash)) {
            p = RSTRING_PTR(str); len = RSTRING_LEN(str);

            if (iter) {
                repl = rb_obj_as_string(rb_yield(match0));
            }
            else {
                repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0));
                repl = rb_obj_as_string(repl);
            }
            str_mod_check(str, p, len);
            rb_check_frozen(str);
        }
        else {
            repl = rb_reg_regsub(repl, str, regs, RB_TYPE_P(pat, T_STRING) ? Qnil : pat);
        }

        enc = rb_enc_compatible(str, repl);
        if (!enc) {
            rb_encoding *str_enc = STR_ENC_GET(str);
            p = RSTRING_PTR(str); len = RSTRING_LEN(str);
            if (coderange_scan(p, beg0, str_enc) != ENC_CODERANGE_7BIT ||
                coderange_scan(p+end0, len-end0, str_enc) != ENC_CODERANGE_7BIT) {
                rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
                         rb_enc_inspect_name(str_enc),
                         rb_enc_inspect_name(STR_ENC_GET(repl)));
            }
            enc = STR_ENC_GET(repl);
        }
        rb_str_modify(str);
        rb_enc_associate(str, enc);
        if (ENC_CODERANGE_UNKNOWN < cr && cr < ENC_CODERANGE_BROKEN) {
            int cr2 = ENC_CODERANGE(repl);
            if (cr2 == ENC_CODERANGE_BROKEN ||
                (cr == ENC_CODERANGE_VALID && cr2 == ENC_CODERANGE_7BIT))
                cr = ENC_CODERANGE_UNKNOWN;
            else
                cr = cr2;
        }
        plen = end0 - beg0;
        rlen = RSTRING_LEN(repl);
        len = RSTRING_LEN(str);
        if (rlen > plen) {
            RESIZE_CAPA(str, len + rlen - plen);
        }
        p = RSTRING_PTR(str);
        if (rlen != plen) {
            memmove(p + beg0 + rlen, p + beg0 + plen, len - beg0 - plen);
        }
        rp = RSTRING_PTR(repl);
        memmove(p + beg0, rp, rlen);
        len += rlen - plen;
        STR_SET_LEN(str, len);
        TERM_FILL(&RSTRING_PTR(str)[len], TERM_LEN(str));
        ENC_CODERANGE_SET(str, cr);

        RB_GC_GUARD(match);

        return str;
    }
    return Qnil;
}
succ → new_str 点击切换源代码

返回 self 的后继。后继是通过递增字符计算的。

要递增的第一个字符是最右边的字母数字字符:或者,如果没有字母数字字符,则是最右边的字符。

'THX1138'.succ # => "THX1139"
'<<koala>>'.succ # => "<<koalb>>"
'***'.succ # => '**+'

数字的后继是另一个数字,从 9 到 0 的“翻转”情况下,将“进位”到左边的下一个字符,并在必要时添加另一个数字。

'00'.succ # => "01"
'09'.succ # => "10"
'99'.succ # => "100"

字母的后继是同一大小写的另一个字母,在翻转的情况下,将进位到左边的下一个字符,并在必要时添加另一个相同大小写的字母。

'aa'.succ # => "ab"
'az'.succ # => "ba"
'zz'.succ # => "aaa"
'AA'.succ # => "AB"
'AZ'.succ # => "BA"
'ZZ'.succ # => "AAA"

非字母数字字符的后继是底层字符集排序序列中的下一个字符,在翻转的情况下,将进位到左边的下一个字符,并在必要时添加另一个字符。

s = 0.chr * 3
s # => "\x00\x00\x00"
s.succ # => "\x00\x00\x01"
s = 255.chr * 3
s # => "\xFF\xFF\xFF"
s.succ # => "\x01\x00\x00\x00"

进位可以在字母数字字符的混合之间发生。

s = 'zz99zz99'
s.succ # => "aaa00aa00"
s = '99zz99zz'
s.succ # => "100aa00aa"

String 的后继是一个新的空 String

''.succ # => ""
VALUE
rb_str_succ(VALUE orig)
{
    VALUE str;
    str = rb_str_new(RSTRING_PTR(orig), RSTRING_LEN(orig));
    rb_enc_cr_str_copy_for_substr(str, orig);
    return str_succ(str);
}
别名为:next
succ! → self 点击切换源代码

等效于 String#succ,但在原地修改 self;返回 self

static VALUE
rb_str_succ_bang(VALUE str)
{
    rb_str_modify(str);
    str_succ(str);
    return str;
}
别名为:next!
sum(n = 16) → integer 点击切换源代码

返回 self 中字符的基本 n 位校验和;校验和是 self 中每个字节的二进制值的总和,模 2**n - 1

'hello'.sum     # => 532
'hello'.sum(4)  # => 4
'hello'.sum(64) # => 532
'тест'.sum      # => 1405
'こんにちは'.sum  # => 2582

这不是一个特别强的校验和。

static VALUE
rb_str_sum(int argc, VALUE *argv, VALUE str)
{
    int bits = 16;
    char *ptr, *p, *pend;
    long len;
    VALUE sum = INT2FIX(0);
    unsigned long sum0 = 0;

    if (rb_check_arity(argc, 0, 1) && (bits = NUM2INT(argv[0])) < 0) {
        bits = 0;
    }
    ptr = p = RSTRING_PTR(str);
    len = RSTRING_LEN(str);
    pend = p + len;

    while (p < pend) {
        if (FIXNUM_MAX - UCHAR_MAX < sum0) {
            sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
            str_mod_check(str, ptr, len);
            sum0 = 0;
        }
        sum0 += (unsigned char)*p;
        p++;
    }

    if (bits == 0) {
        if (sum0) {
            sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
        }
    }
    else {
        if (sum == INT2FIX(0)) {
            if (bits < (int)sizeof(long)*CHAR_BIT) {
                sum0 &= (((unsigned long)1)<<bits)-1;
            }
            sum = LONG2FIX(sum0);
        }
        else {
            VALUE mod;

            if (sum0) {
                sum = rb_funcall(sum, '+', 1, LONG2FIX(sum0));
            }

            mod = rb_funcall(INT2FIX(1), idLTLT, 1, INT2FIX(bits));
            mod = rb_funcall(mod, '-', 1, INT2FIX(1));
            sum = rb_funcall(sum, '&', 1, mod);
        }
    }
    return sum;
}
swapcase(*options) → string 点击切换源代码

返回一个包含 self 中字符的字符串,其中大小写反转;每个大写字符都转换为小写;每个小写字符都转换为大写。

s = 'Hello World!' # => "Hello World!"
s.swapcase         # => "hELLO wORLD!"

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关链接:String#swapcase!

static VALUE
rb_str_swapcase(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;
    VALUE ret;

    flags = check_case_options(argc, argv, flags);
    enc = str_true_enc(str);
    if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return str_duplicate(rb_cString, str);
    if (flags&ONIGENC_CASE_ASCII_ONLY) {
        ret = rb_str_new(0, RSTRING_LEN(str));
        rb_str_ascii_casemap(str, ret, &flags, enc);
    }
    else {
        ret = rb_str_casemap(str, &flags, enc);
    }
    return ret;
}
swapcase!(*options) → self or nil 点击切换源代码

self 中每个小写字符转换为大写;将大写字符转换为小写;如果进行了任何更改,则返回 self,否则返回 nil

s = 'Hello World!' # => "Hello World!"
s.swapcase!        # => "hELLO wORLD!"
s                  # => "hELLO wORLD!"
''.swapcase!       # => nil

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关链接:String#swapcase

static VALUE
rb_str_swapcase_bang(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_UPCASE | ONIGENC_CASE_DOWNCASE;

    flags = check_case_options(argc, argv, flags);
    str_modify_keep_cr(str);
    enc = str_true_enc(str);
    if (flags&ONIGENC_CASE_ASCII_ONLY)
        rb_str_ascii_casemap(str, str, &flags, enc);
    else
        str_shared_replace(str, rb_str_casemap(str, &flags, enc));

    if (ONIGENC_CASE_MODIFIED&flags) return str;
    return Qnil;
}
to_c → complex 点击切换源代码

返回将 self 解释为 Complex 对象的结果;忽略前导空格和尾随垃圾字符。

'9'.to_c                 # => (9+0i)
'2.5'.to_c               # => (2.5+0i)
'2.5/1'.to_c             # => ((5/2)+0i)
'-3/2'.to_c              # => ((-3/2)+0i)
'-i'.to_c                # => (0-1i)
'45i'.to_c               # => (0+45i)
'3-4i'.to_c              # => (3-4i)
'-4e2-4e-2i'.to_c        # => (-400.0-0.04i)
'-0.0-0.0i'.to_c         # => (-0.0-0.0i)
'1/2+3/4i'.to_c          # => ((1/2)+(3/4)*i)
'1.0@0'.to_c             # => (1+0.0i)
"1.0@#{Math::PI/2}".to_c # => (0.0+1i)
"1.0@#{Math::PI}".to_c   # => (-1+0.0i)

如果字符串无法转换,则返回复数零。

'ruby'.to_c        # => (0+0i)

请参阅 Kernel#Complex

static VALUE
string_to_c(VALUE self)
{
    VALUE num;

    rb_must_asciicompat(self);

    (void)parse_comp(rb_str_fill_terminator(self, 1), FALSE, &num);

    return num;
}
to_f → float 点击切换源代码

返回将 self 中的前导字符解释为 Float 的结果。

'3.14159'.to_f  # => 3.14159
'1.234e-2'.to_f # => 0.01234

忽略前导有效数字(在给定的 base 中)之后的字符。

'3.14 (pi to two places)'.to_f # => 3.14

如果没有前导有效数字,则返回零。

'abcdef'.to_f # => 0.0
static VALUE
rb_str_to_f(VALUE str)
{
    return DBL2NUM(rb_str_to_dbl(str, FALSE));
}
to_i(base = 10) → integer 点击切换源代码

返回将 self 中的前导字符解释为给定 base(必须在 (0, 2..36) 范围内)的整数的结果。

'123456'.to_i     # => 123456
'123def'.to_i(16) # => 1195503

base 为零时,字符串 object 可能包含前导字符以指定实际的基数。

'123def'.to_i(0)   # => 123
'0123def'.to_i(0)  # => 83
'0b123def'.to_i(0) # => 1
'0o123def'.to_i(0) # => 83
'0d123def'.to_i(0) # => 123
'0x123def'.to_i(0) # => 1195503

忽略前导有效数字(在给定的 base 中)之后的字符。

'12.345'.to_i   # => 12
'12345'.to_i(2) # => 1

如果没有前导有效数字,则返回零。

'abcdef'.to_i # => 0
'2'.to_i(2)   # => 0
static VALUE
rb_str_to_i(int argc, VALUE *argv, VALUE str)
{
    int base = 10;

    if (rb_check_arity(argc, 0, 1) && (base = NUM2INT(argv[0])) < 0) {
        rb_raise(rb_eArgError, "invalid radix %d", base);
    }
    return rb_str_to_inum(str, base, FALSE);
}
to_r → rational 点击切换源代码

返回将 str 中的前导字符解释为有理数的结果。忽略前导空格和有效数字末尾之后的多余字符。数字序列可以用下划线分隔。如果 str 的开头没有有效的数字,则返回零。此方法永远不会引发异常。

'  2  '.to_r       #=> (2/1)
'300/2'.to_r       #=> (150/1)
'-9.2'.to_r        #=> (-46/5)
'-9.2e2'.to_r      #=> (-920/1)
'1_234_567'.to_r   #=> (1234567/1)
'21 June 09'.to_r  #=> (21/1)
'21/06/09'.to_r    #=> (7/2)
'BWV 1079'.to_r    #=> (0/1)

注意:“0.3”.to_r 与 0.3.to_r 不同。前者等价于 “3/10”.to_r,但后者不是。

"0.3".to_r == 3/10r  #=> true
0.3.to_r   == 3/10r  #=> false

另请参阅 Kernel#Rational

static VALUE
string_to_r(VALUE self)
{
    VALUE num;

    rb_must_asciicompat(self);

    num = parse_rat(RSTRING_PTR(self), RSTRING_END(self), 0, TRUE);

    if (RB_FLOAT_TYPE_P(num) && !FLOAT_ZERO_P(num))
        rb_raise(rb_eFloatDomainError, "Infinity");
    return num;
}
to_s → self or string 点击切换源代码

如果 selfString,则返回 self;如果 selfString 的子类,则返回转换为 Stringself

static VALUE
rb_str_to_s(VALUE str)
{
    if (rb_obj_class(str) != rb_cString) {
        return str_duplicate(rb_cString, str);
    }
    return str;
}
别名为:to_str
to_str()

如果 selfString,则返回 self;如果 selfString 的子类,则返回转换为 Stringself

to_s 的别名:to_s
to_sym → symbol

返回与 str 相对应的 Symbol,如果该符号以前不存在,则创建该符号。请参阅 Symbol#id2name

"Koala".intern         #=> :Koala
s = 'cat'.to_sym       #=> :cat
s == :cat              #=> true
s = '@cat'.to_sym      #=> :@cat
s == :@cat             #=> true

这也可用于创建不能使用 :xxx 表示法表示的符号。

'cat and dog'.to_sym   #=> :"cat and dog"
intern 的别名:intern
tr(selector, replacements) → new_string 点击切换源代码

返回 self 的副本,其中字符串 selector 指定的每个字符都转换为字符串 replacements 中的相应字符。对应关系是位置的

  • selector 指定的第一个字符的每次出现都转换为 replacements 中的第一个字符。

  • selector 指定的第二个字符的每次出现都转换为 replacements 中的第二个字符。

  • 依此类推。

示例

'hello'.tr('el', 'ip') #=> "hippo"

如果 replacementsselector 短,则会隐式使用其最后一个字符进行填充。

'hello'.tr('aeiou', '-')   # => "h-ll-"
'hello'.tr('aeiou', 'AA-') # => "hAll-"

参数 selectorreplacements 必须是有效的字符选择器(请参阅 字符选择器),并且可以使用其任何有效形式,包括否定、范围和转义。

# Negation.
'hello'.tr('^aeiou', '-') # => "-e--o"
# Ranges.
'ibm'.tr('b-z', 'a-z') # => "hal"
# Escapes.
'hel^lo'.tr('\^aeiou', '-')     # => "h-l-l-"    # Escaped leading caret.
'i-b-m'.tr('b\-z', 'a-z')       # => "ibabm"     # Escaped embedded hyphen.
'foo\\bar'.tr('ab\\', 'XYZ')    # => "fooZYXr"   # Escaped backslash.
static VALUE
rb_str_tr(VALUE str, VALUE src, VALUE repl)
{
    str = str_duplicate(rb_cString, str);
    tr_trans(str, src, repl, 0);
    return str;
}
tr!(selector, replacements) → self or nil 点击切换源代码

String#tr 类似,但会就地修改 self。如果进行了任何更改,则返回 self,否则返回 nil

static VALUE
rb_str_tr_bang(VALUE str, VALUE src, VALUE repl)
{
    return tr_trans(str, src, repl, 0);
}
tr_s(selector, replacements) → string 点击切换源代码

String#tr 类似,但也会挤压已翻译字符串的修改部分;返回一个新字符串(已翻译并已挤压)。

'hello'.tr_s('l', 'r')   #=> "hero"
'hello'.tr_s('el', '-')  #=> "h-o"
'hello'.tr_s('el', 'hx') #=> "hhxo"

相关链接:String#squeeze

static VALUE
rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
{
    str = str_duplicate(rb_cString, str);
    tr_trans(str, src, repl, 1);
    return str;
}
tr_s!(selector, replacements) → self or nil 点击切换源代码

String#tr_s 类似,但会就地修改 self。如果进行了任何更改,则返回 self,否则返回 nil

相关链接:String#squeeze!

static VALUE
rb_str_tr_s_bang(VALUE str, VALUE src, VALUE repl)
{
    return tr_trans(str, src, repl, 1);
}
undump → string 点击切换源代码

返回 self 的未转义版本。

s_orig = "\f\x00\xff\\\""    # => "\f\u0000\xFF\\\""
s_dumped = s_orig.dump       # => "\"\\f\\x00\\xFF\\\\\\\"\""
s_undumped = s_dumped.undump # => "\f\u0000\xFF\\\""
s_undumped == s_orig         # => true

相关链接:String#dumpString#undump 的反向操作)。

static VALUE
str_undump(VALUE str)
{
    const char *s = RSTRING_PTR(str);
    const char *s_end = RSTRING_END(str);
    rb_encoding *enc = rb_enc_get(str);
    VALUE undumped = rb_enc_str_new(s, 0L, enc);
    bool utf8 = false;
    bool binary = false;
    int w;

    rb_must_asciicompat(str);
    if (rb_str_is_ascii_only_p(str) == Qfalse) {
        rb_raise(rb_eRuntimeError, "non-ASCII character detected");
    }
    if (!str_null_check(str, &w)) {
        rb_raise(rb_eRuntimeError, "string contains null byte");
    }
    if (RSTRING_LEN(str) < 2) goto invalid_format;
    if (*s != '"') goto invalid_format;

    /* strip '"' at the start */
    s++;

    for (;;) {
        if (s >= s_end) {
            rb_raise(rb_eRuntimeError, "unterminated dumped string");
        }

        if (*s == '"') {
            /* epilogue */
            s++;
            if (s == s_end) {
                /* ascii compatible dumped string */
                break;
            }
            else {
                static const char force_encoding_suffix[] = ".force_encoding(\""; /* "\")" */
                static const char dup_suffix[] = ".dup";
                const char *encname;
                int encidx;
                ptrdiff_t size;

                /* check separately for strings dumped by older versions */
                size = sizeof(dup_suffix) - 1;
                if (s_end - s > size && memcmp(s, dup_suffix, size) == 0) s += size;

                size = sizeof(force_encoding_suffix) - 1;
                if (s_end - s <= size) goto invalid_format;
                if (memcmp(s, force_encoding_suffix, size) != 0) goto invalid_format;
                s += size;

                if (utf8) {
                    rb_raise(rb_eRuntimeError, "dumped string contained Unicode escape but used force_encoding");
                }

                encname = s;
                s = memchr(s, '"', s_end-s);
                size = s - encname;
                if (!s) goto invalid_format;
                if (s_end - s != 2) goto invalid_format;
                if (s[0] != '"' || s[1] != ')') goto invalid_format;

                encidx = rb_enc_find_index2(encname, (long)size);
                if (encidx < 0) {
                    rb_raise(rb_eRuntimeError, "dumped string has unknown encoding name");
                }
                rb_enc_associate_index(undumped, encidx);
            }
            break;
        }

        if (*s == '\\') {
            s++;
            if (s >= s_end) {
                rb_raise(rb_eRuntimeError, "invalid escape");
            }
            undump_after_backslash(undumped, &s, s_end, &enc, &utf8, &binary);
        }
        else {
            rb_str_cat(undumped, s++, 1);
        }
    }

    RB_GC_GUARD(str);

    return undumped;
invalid_format:
    rb_raise(rb_eRuntimeError, "invalid dumped string; not wrapped with '\"' nor '\"...\".force_encoding(\"...\")' form");
}
unicode_normalize(form = :nfc) → string 点击切换源代码

返回应用了 Unicode 规范化self 的副本。

参数 form 必须是以下符号之一(请参阅 Unicode 规范化形式):

  • :nfc:规范分解,然后进行规范组合。

  • :nfd:规范分解。

  • :nfkc:兼容性分解,然后进行规范组合。

  • :nfkd:兼容性分解。

self 的编码必须是以下之一:

  • Encoding::UTF_8

  • Encoding::UTF_16BE

  • Encoding::UTF_16LE

  • Encoding::UTF_32BE

  • Encoding::UTF_32LE

  • Encoding::GB18030

  • Encoding::UCS_2BE

  • Encoding::UCS_4BE

示例

"a\u0300".unicode_normalize      # => "a"
"\u00E0".unicode_normalize(:nfd) # => "a "

相关链接:String#unicode_normalize!, String#unicode_normalized?

static VALUE
rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)
{
    return unicode_normalize_common(argc, argv, str, id_normalize);
}
unicode_normalize!(form = :nfc) → self 点击切换源代码

String#unicode_normalize 类似,不同之处在于规范化是在 self 上执行的。

相关链接:String#unicode_normalized?

static VALUE
rb_str_unicode_normalize_bang(int argc, VALUE *argv, VALUE str)
{
    return rb_str_replace(str, unicode_normalize_common(argc, argv, str, id_normalize));
}
unicode_normalized?(form = :nfc) → true or false 点击切换源代码

如果 self 处于给定的 Unicode 规范化 form 中,则返回 true,否则返回 falseform 必须是 :nfc:nfd:nfkc:nfkd 之一。

示例

"a\u0300".unicode_normalized?       # => false
"a\u0300".unicode_normalized?(:nfd) # => true
"\u00E0".unicode_normalized?        # => true
"\u00E0".unicode_normalized?(:nfd)  # => false

如果 self 不是 Unicode 编码,则引发异常。

s = "\xE0".force_encoding('ISO-8859-1')
s.unicode_normalized? # Raises Encoding::CompatibilityError.

相关链接:String#unicode_normalize, String#unicode_normalize!

static VALUE
rb_str_unicode_normalized_p(int argc, VALUE *argv, VALUE str)
{
    return unicode_normalize_common(argc, argv, str, id_normalized_p);
}
unpack(template, offset: 0, &block) → array 点击切换源代码

self 中提取数据。

如果未给定 block,则会形成成为新数组元素的各个对象,并返回该数组。否则,会产生每个对象。

请参阅 压缩数据

# File ruby_3_4_1/pack.rb, line 23
def unpack(fmt, offset: 0)
  Primitive.attr! :use_block
  Primitive.pack_unpack(fmt, offset)
end
unpack1(template, offset: 0) → object 点击切换源代码

String#unpack 类似,但仅解压并返回第一个提取的对象。请参阅 压缩数据

# File ruby_3_4_1/pack.rb, line 33
def unpack1(fmt, offset: 0)
  Primitive.pack_unpack1(fmt, offset)
end
upcase(*options) → string 点击切换源代码

返回一个包含 self 中大写字符的字符串。

s = 'Hello World!' # => "Hello World!"
s.upcase           # => "HELLO WORLD!"

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关链接:String#upcase!, String#downcase, String#downcase!

static VALUE
rb_str_upcase(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;
    VALUE ret;

    flags = check_case_options(argc, argv, flags);
    enc = str_true_enc(str);
    if (case_option_single_p(flags, enc, str)) {
        ret = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
        str_enc_copy_direct(ret, str);
        upcase_single(ret);
    }
    else if (flags&ONIGENC_CASE_ASCII_ONLY) {
        ret = rb_str_new(0, RSTRING_LEN(str));
        rb_str_ascii_casemap(str, ret, &flags, enc);
    }
    else {
        ret = rb_str_casemap(str, &flags, enc);
    }

    return ret;
}
upcase!(*options) → self or nil 点击切换源代码

self 中的字符转换为大写;如果进行了任何更改,则返回 self,否则返回 nil

s = 'Hello World!' # => "Hello World!"
s.upcase!          # => "HELLO WORLD!"
s                  # => "HELLO WORLD!"
s.upcase!          # => nil

大小写可能会受到给定 options 的影响;请参阅 大小写映射

相关链接:String#upcase, String#downcase, String#downcase!

static VALUE
rb_str_upcase_bang(int argc, VALUE *argv, VALUE str)
{
    rb_encoding *enc;
    OnigCaseFoldType flags = ONIGENC_CASE_UPCASE;

    flags = check_case_options(argc, argv, flags);
    str_modify_keep_cr(str);
    enc = str_true_enc(str);
    if (case_option_single_p(flags, enc, str)) {
        if (upcase_single(str))
            flags |= ONIGENC_CASE_MODIFIED;
    }
    else if (flags&ONIGENC_CASE_ASCII_ONLY)
        rb_str_ascii_casemap(str, str, &flags, enc);
    else
        str_shared_replace(str, rb_str_casemap(str, &flags, enc));

    if (ONIGENC_CASE_MODIFIED&flags) return str;
    return Qnil;
}
upto(other_string, exclusive = false) {|string| ... } → self 点击切换源代码
upto(other_string, exclusive = false) → new_enumerator

如果给定了块,则会使用对 String#succ 的连续调用返回的每个 String 值来调用该块;第一个值是 self,下一个值是 self.succ,依此类推;当达到值 other_string 时,序列终止;返回 self

'a8'.upto('b6') {|s| print s, ' ' } # => "a8"

输出

a8 a9 b0 b1 b2 b3 b4 b5 b6

如果参数 exclusive 作为真值对象给出,则最后一个值将被省略。

'a8'.upto('b6', true) {|s| print s, ' ' } # => "a8"

输出

a8 a9 b0 b1 b2 b3 b4 b5

如果无法达到 other_string,则不会调用该块。

'25'.upto('5') {|s| fail s }
'aa'.upto('a') {|s| fail s }

如果未给定块,则返回一个新的 Enumerator。

'a8'.upto('b6') # => #<Enumerator: "a8":upto("b6")>
static VALUE
rb_str_upto(int argc, VALUE *argv, VALUE beg)
{
    VALUE end, exclusive;

    rb_scan_args(argc, argv, "11", &end, &exclusive);
    RETURN_ENUMERATOR(beg, argc, argv);
    return rb_str_upto_each(beg, end, RTEST(exclusive), str_upto_i, Qnil);
}
valid_encoding? → true or false 点击切换源代码

如果 self 被正确编码,则返回 true,否则返回 false

"\xc2\xa1".force_encoding("UTF-8").valid_encoding? # => true
"\xc2".force_encoding("UTF-8").valid_encoding?     # => false
"\x80".force_encoding("UTF-8").valid_encoding?     # => false
static VALUE
rb_str_valid_encoding_p(VALUE str)
{
    int cr = rb_enc_str_coderange(str);

    return RBOOL(cr != ENC_CODERANGE_BROKEN);
}