class String
字符串对象包含任意字节序列,通常表示文本或二进制数据。可以使用 String::new
或字面量创建字符串对象。
String
对象不同于 Symbol
对象,因为 Symbol
对象被设计为用作标识符,而不是文本或数据。
您可以使用以下方法显式创建字符串对象:
您可以使用以下方法将某些对象转换为字符串:
-
方法
String
。
一些字符串方法会修改 self
。通常,方法名以 !
结尾的方法会修改 self
并返回 self
;通常,类似命名的(没有 !
)方法会返回一个新的字符串。
一般来说,如果存在 bang 和非 bang 版本的方法,bang! 会修改,非 bang! 不会。但是,没有 bang 的方法也可以修改,例如 String#replace
。
替换方法¶ ↑
这些方法执行替换
-
String#sub
: 一次替换(或不替换);返回一个新的字符串。 -
String#sub!
: 一次替换(或不替换);返回self
。 -
String#gsub
: 零次或多次替换;返回一个新的字符串。 -
String#gsub!
: 零次或多次替换;返回self
。
这些方法中的每一个都接受以下参数:
-
第一个参数
pattern
(字符串或正则表达式),指定要替换的子字符串。 -
以下任一参数:
-
第二个参数
replacement
(字符串或哈希),确定替换字符串。 -
一个将确定替换字符串的代码块。
-
本节中的示例主要使用 String#sub
和 String#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
是一个字符串时,它的所有字符都被视为普通字符(而不是正则表达式特殊字符)
'THX1138'.gsub('\d+', '00') # => "THX1138"
字符串 replacement
如果 replacement
是一个字符串,该字符串将确定要替换匹配文本的替换字符串。
以上每个示例都使用一个简单的字符串作为替换字符串。
字符串 replacement
可能包含对模式捕获的回溯引用
-
\n
(n 是一个非负整数)指的是$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(空字符):
"\x00"
,"\u0000"
。 -
HT(水平制表符):
"\x09"
,"\t"
。 -
LF(换行符):
"\x0a"
,"\n"
。 -
VT(垂直制表符):
"\x0b"
,"\v"
。 -
FF(换页符):
"\x0c"
,"\f"
。 -
CR(回车符):
"\x0d"
,"\r"
。 -
SP(空格):
"\x20"
," "
。
空白字符与以下方法相关
字符串切片¶ ↑
字符串的切片 是通过特定条件选择的子字符串。
以下实例方法使用切片
-
String#[]
(也称为String#slice
)返回从self
复制的切片。 -
String#[]=
返回self
的副本,其中切片被替换。 -
String#slice!
返回self
,其中切片被移除。
以上每个方法都接受确定要复制或替换的切片的参数。
参数有多种形式。对于字符串 string
,形式如下
-
string[index]
. -
string[start, length]
. -
string[range]
. -
string[regexp, capture = 0]
. -
string[substring]
.
string[index]
当给出非负整数参数 index
时,切片是在 self
中字符偏移量为 index
的位置找到的 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]
当给出非负整数参数 start
和 length
时,切片从字符偏移量 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
,则它应该是一个捕获组索引(整数)或一个捕获组名称(字符串或符号);切片是指定的捕获(参见 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 类
-
继承自 Object 类。
-
包含 Comparable 模块。
这里,String 类提供了对以下内容有用的方法:
创建字符串的方法¶ ↑
-
::new
: 返回一个新的字符串。 -
::try_convert
: 返回一个由给定对象创建的新字符串。
冻结/未冻结 String
的方法¶ ↑
-
+@
: 返回一个未冻结的字符串:如果未冻结,则为self
;否则为self.dup
。 -
-@
: 返回一个冻结的字符串:如果已冻结,则为self
;否则为self.freeze
。 -
freeze
: 如果self
未冻结,则冻结self
;返回self
。
查询方法¶ ↑
计数
子字符串
-
index
: 返回给定子字符串的第一个出现的索引;如果未找到,则返回nil
。 -
rindex
: 返回给定子字符串的最后一个出现的索引;如果未找到,则返回nil
。 -
include?
: 如果字符串包含给定的子字符串,则返回true
;否则返回false
。 -
start_with?
: 如果字符串以任何给定的子字符串开头,则返回true
。 -
end_with?
: 如果字符串以任何给定的子字符串结尾,则返回true
。
编码
-
unicode_normalized?
: 如果字符串处于 Unicode 规范化形式,则返回true
;否则返回false
。 -
valid_encoding?
: 如果字符串仅包含对其编码有效的字符,则返回true
。 -
ascii_only?
: 如果字符串仅包含 ASCII 字符,则返回true
;否则返回false
。
其他
比较方法¶ ↑
-
eql?
: 如果内容与给定的另一个字符串相同,则返回true
。 -
<=>
: 如果给定的另一个字符串小于、等于或大于self
,则分别返回 -1、0 或 1。 -
casecmp
: 忽略大小写,如果给定的另一个字符串小于、等于或大于self
,则分别返回 -1、0 或 1。 -
casecmp?
: 如果字符串在 Unicode 大小写折叠后等于给定字符串,则返回true
;否则返回false
。
修改字符串的方法¶ ↑
这些方法中的每一个都会修改self
。
插入
替换
-
sub!
: 用给定的替换字符串替换与给定模式匹配的第一个子字符串;如果进行了任何更改,则返回self
,否则返回nil
。 -
gsub!
: 用给定的替换字符串替换与给定模式匹配的每个子字符串;如果进行了任何更改,则返回self
,否则返回nil
。 -
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
。 -
squeeze!
: 删除连续的重复字符;返回self
。 -
delete!
: 删除由子字符串参数的交集确定的字符。 -
lstrip!
: 删除前导空格;如果存在任何更改,则返回self
,否则返回nil
。 -
rstrip!
: 删除尾随空格;如果存在任何更改,则返回self
,否则返回nil
。 -
strip!
: 删除前导和尾随空格;如果存在任何更改,则返回self
,否则返回nil
。 -
chomp!
: 如果找到,则删除尾部的记录分隔符;如果进行了任何更改,则返回self
,否则返回nil
。 -
chop!
: 如果找到,则删除尾部的换行符;否则删除最后一个字符;如果进行了任何更改,则返回self
,否则返回nil
。
转换为新字符串的方法¶ ↑
这些方法中的每一个都返回一个基于self
的新字符串,通常只是self
的修改副本。
扩展
-
*
: 返回self
的多个副本的串联。 -
+
: 返回self
与给定其他字符串的串联。 -
center
: 返回self
的副本,在填充子字符串之间居中。 -
concat
: 返回self
与给定其他字符串的串联。 -
prepend
: 返回给定其他字符串与self
的串联。 -
ljust
: 返回self
的副本,长度为给定长度,右侧填充给定其他字符串。 -
rjust
: 返回self
的副本,长度为给定长度,左侧填充给定其他字符串。
编码
-
b
: 返回self
的副本,使用 ASCII-8BIT 编码。 -
scrub
: 返回self
的副本,其中每个无效字节都被替换为给定字符。 -
unicode_normalize
: 返回self
的副本,其中每个字符都进行了 Unicode 规范化。 -
encode
: 返回self
的副本,其中所有字符都从给定编码转换为另一个编码。
替换
-
dump
: 返回self
的副本,其中所有非打印字符都被替换为 xHH 表示法,所有特殊字符都被转义。 -
undump
: 返回self
的副本,其中所有\xNN
表示法都被替换为\uNNNN
表示法,所有转义字符都被取消转义。 -
sub
: 返回self
的副本,其中第一个与给定模式匹配的子字符串被替换为给定替换字符串;。 -
gsub
: 返回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
的副本,其中删除了连续的重复字符。 -
byteslice
: 返回由给定索引、开始/长度或范围确定的子字符串。 -
chr
: 返回第一个字符。
复制
-
to_s
, $to_str: 如果self
是 String 的子类,则返回复制到 String 中的self
;否则,返回self
。
转换为非字符串的方法¶ ↑
这些方法中的每一个都将 self
的内容转换为非字符串。
字符、字节和集群
-
bytes
: 返回self
中字节的数组。 -
chars
: 返回一个包含self
中所有字符的数组。 -
codepoints
: 返回一个包含self
中所有整数序数值的数组。 -
getbyte
: 返回由给定索引确定的整数字节。 -
grapheme_clusters
: 返回一个包含self
中所有音节的数组。
分割
-
lines
: 返回一个包含self
中所有行的数组,由给定的记录分隔符确定。 -
partition
: 返回一个包含 3 个元素的数组,由第一个匹配给定子字符串或正则表达式的子字符串确定。 -
rpartition
: 返回一个包含 3 个元素的数组,由最后一个匹配给定子字符串或正则表达式的子字符串确定。 -
split
: 返回一个由给定分隔符(正则表达式或字符串)确定的子字符串数组,或者如果给定一个块,则将这些子字符串传递给该块。
匹配
-
scan
: 返回一个包含与给定正则表达式或字符串匹配的子字符串的数组,或者如果给定一个块,则将每个匹配的子字符串传递给该块。 -
unpack
: 返回一个根据给定格式从self
中提取的子字符串数组。 -
unpack1
: 返回根据给定格式从self
中提取的第一个子字符串。
数值
-
hex
: 返回前导字符的整数值,解释为十六进制数字。 -
oct
: 返回前导字符的整数值,解释为八进制数字。 -
ord
: 返回self
中第一个字符的整数序数值。 -
to_i
: 返回前导字符的整数值,解释为一个整数。 -
to_f
: 返回前导字符的浮点值,解释为一个浮点数。
字符串和符号
用于迭代的方法¶ ↑
-
each_byte
: 使用self
中的每个连续字节调用给定的块。 -
each_char
: 使用self
中的每个连续字符调用给定的块。 -
each_codepoint
: 使用self
中的每个连续整数代码点调用给定的块。 -
each_grapheme_cluster
: 对self
中的每个连续的字形簇调用给定的代码块。 -
each_line
: 对self
中的每个连续行调用给定的代码块,由给定的记录分隔符确定。
公共类方法
返回一个新的 String 对象,它是 string
的副本。
如果没有参数,则返回具有 Encoding
ASCII-8BIT
的空字符串。
s = String.new s # => "" s.encoding # => #<Encoding:ASCII-8BIT>
如果只有一个可选参数 string
且没有关键字参数,则返回具有相同编码的 string
的副本。
String.new('foo') # => "foo" String.new('тест') # => "тест" String.new('こんにちは') # => "こんにちは"
(与 String.new 不同,字符串字面量(如 ''
)或 这里文档字面量 始终具有 脚本编码。)
如果有一个可选的关键字参数 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)
string
、encoding
和 capacity
参数可以一起使用。
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)) { /* make noembed always */ char *new_ptr = ALLOC_N(char, (size_t)capa + termlen); assert(RSTRING_LEN(str) + 1 <= str_embed_capa(str)); memcpy(new_ptr, RSTRING(str)->as.embed.ary, RSTRING_LEN(str) + 1); RSTRING(str)->as.heap.ptr = new_ptr; } else if (FL_TEST(str, STR_SHARED|STR_NOFREE)) { 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_t)capa + termlen); 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; }
如果 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); }
公共实例方法
返回将object
格式化为self
格式规范的结果(有关格式化详细信息,请参见Kernel#sprintf
)。
"%05d" % 123 # => "00123"
如果self
包含多个替换,则object
必须是包含要替换值的Array
或Hash
。
"%-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); }
返回一个新的字符串,其中包含integer
个self
的副本。
"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_new0(rb_cString, 0, len, termlen); 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; }
返回一个新的字符串,其中包含other_string
连接到self
。
"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_new0(rb_cString, 0, len1+len2, termlen); 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; }
如果self
未冻结,则返回self
。
否则返回self.dup
,它未冻结。
static VALUE str_uplus(VALUE str) { if (OBJ_FROZEN(str)) { return rb_str_dup(str); } else { return str; } }
返回字符串的冻结副本,该副本可能已存在。
只要返回的字符串没有设置任何实例变量,并且不是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); }
将object
连接到self
并返回self
。
s = 'foo' s << 'bar' # => "foobar" s # => "foobar"
如果object
是Integer
,则该值被视为代码点,并在连接之前转换为字符。
s = 'foo' s << 33 # => "foo!"
相关: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) { char buf[1]; buf[0] = (char)code; rb_str_cat(str1, buf, 1); if (encidx != rb_enc_to_index(enc)) { rb_enc_associate_index(str1, encidx); ENC_CODERANGE_SET(str1, ENC_CODERANGE_VALID); } } 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; }
比较self
和other_string
,返回
-
-1 如果
other_string
更大。 -
0 如果两者相等。
-
1 如果
other_string
更小。 -
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); }
如果 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); }
如果 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.==
比较两个字符串。
返回与给定 regexp
匹配的第一个子字符串的 Integer
索引,如果未找到匹配项,则返回 nil
。
'foo' =~ /f/ # => 0 'foo' =~ /o/ # => 1 'foo' =~ /x/ # => nil
注意:还会更新 Regexp
中的全局变量。
如果给定的 object
不是 Regexp
,则返回 object =~ self
返回的值。
注意,string =~ regexp
与 regexp =~ 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); } }
返回由参数指定的 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 { long beg = NUM2LONG(argv[0]); long len = NUM2LONG(argv[1]); return rb_str_substr(str, beg, len); } } rb_check_arity(argc, 1, 2); return rb_str_aref(str, argv[0]); }
替换 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]); }
如果 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); }
返回一个具有 ASCII-8BIT 编码的 self
副本;底层字节不会被修改
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; }
返回给定 substring
第一次出现的基于字节的索引,如果未找到则返回 nil
'foo'.byteindex('f') # => 0 'foo'.byteindex('o') # => 1 'foo'.byteindex('oo') # => 1 'foo'.byteindex('ooo') # => nil
返回给定 Regexp
regexp
的第一个匹配项的基于字节的索引,如果未找到则返回 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#index
,String#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; }
返回给定 substring
的最后一次出现的基于字节的索引,如果未找到则返回 nil
'foo'.byterindex('f') # => 0 'foo'.byterindex('o') # => 2 'foo'.byterindex('oo') # => 1 'foo'.byterindex('ooo') # => nil
返回给定 Regexp
regexp
的最后一次匹配的基于字节的索引,如果未找到则返回 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
且为非负数,则指定字符串中开始搜索的最大基于字节的位置
string to _end_ the search: '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; }
返回 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); }
返回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)); }
返回self
的子字符串,如果无法构造子字符串,则返回nil
。
给定整数参数index
和length
,返回从给定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]); }
用str
替换self
的部分或全部内容,并返回self
。受影响的字符串部分使用与String#byteslice
相同的标准确定,但length
不能省略。如果替换字符串与它替换的文本长度不同,则字符串将相应调整。
如果给出str_index
和str_length
或str_range
,则self
的内容将被str.byteslice(str_index, str_length)或str.byteslice(str_range)替换;但是,str
的子字符串不会作为新字符串分配。
采用Integer
的形式,如果值超出范围,将引发IndexError
;Range
形式将引发RangeError
。如果开始或结束偏移量未落在字符(代码点)边界上,将引发IndexError
。
static VALUE rb_str_bytesplice(int argc, VALUE *argv, VALUE str) { long beg, len, vbeg, vlen; VALUE val; rb_encoding *enc; 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); enc = rb_enc_check(str, val); str_modify_keep_cr(str); rb_str_update_1(str, beg, len, val, vbeg, vlen); rb_enc_associate(str, enc); cr = ENC_CODERANGE_AND(ENC_CODERANGE(str), ENC_CODERANGE(val)); if (cr != ENC_CODERANGE_BROKEN) ENC_CODERANGE_SET(str, cr); return str; }
返回一个包含self
中字符的字符串;第一个字符大写;其余字符小写。
s = 'hello World!' # => "hello World!" s.capitalize # => "Hello world!"
大小写可能受给定的options
影响;参见大小写映射。
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; }
将self
中的第一个字符大写;将其余字符小写;如果进行了任何更改,则返回self
,否则返回nil
。
s = 'hello World!' # => "hello World!" s.capitalize! # => "Hello world!" s # => "Hello world!" s.capitalize! # => nil
大小写可能受给定的options
影响;参见大小写映射。
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; }
比较self.downcase
和other_string.downcase
;返回
-
-1 如果
other_string.downcase
更大。 -
0 如果两者相等。
-
1 如果
other_string.downcase
更小。 -
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); }
如果self
和other_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); }
返回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"
static VALUE rb_str_center(int argc, VALUE *argv, VALUE str) { return rb_str_justify(argc, argv, str, 'c'); }
返回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); }
返回一个从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)); }
类似于 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); }
返回一个从 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)); }
类似于 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; }
返回包含 self
的第一个字符的字符串。
s = 'foo' # => "foo" s.chr # => "f"
static VALUE rb_str_chr(VALUE str) { return rb_str_substr(str, 0, 1); }
移除 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; }
返回 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); }
将 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; }
返回 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(3)
标准库函数生成的字符串,该函数以str
和salt_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
子类,它就会被去重。
请注意,-string
变体更便于定义常量
FILENAME = -'config/database.yml'
而dedup
更适合在计算链中使用该方法。
@url_list.concat(urls.map(&:dedup))
返回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; }
类似于 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; }
返回一个 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); }
类似于 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); }
返回一个 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); }
类似于 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; }
返回一个字符串,其中包含 self
中的小写字符
s = 'Hello World!' # => "Hello World!" s.downcase # => "hello world!"
大小写可能受给定的options
影响;参见大小写映射。
相关:String#downcase!
,String#upcase
,String#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; }
将 self
中的字符转换为小写;如果进行了任何更改,则返回 self
,否则返回 nil
s = 'Hello World!' # => "Hello World!" s.downcase! # => "hello world!" s # => "hello world!" s.downcase! # => nil
大小写可能受给定的options
影响;参见大小写映射。
相关:String#downcase
,String#upcase
,String#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; }
返回 self
的可打印版本,用双引号括起来,特殊字符转义,非打印字符用十六进制表示法替换
"hello \n ''".dump # => "\"hello \\n ''\"" "\f\x00\xff\\\"".dump # => "\"\\f\\x00\\xFF\\\\\\\"\""
相关:String#undump
(String#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; }
使用 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); }
使用 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); }
使用 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); }
使用 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); }
如果给出代码块,则形成子字符串(“行”),这些子字符串是通过在 self
中的每个给定行分隔符 line_sep
处分割而产生的;将每行传递给代码块;返回 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"
如果 chomp
为 true
,则从每行中删除尾随的 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); }
如果 self
的长度为零,则返回 true
,否则返回 false
"hello".empty? # => false " ".empty? # => false "".empty? # => true
static VALUE rb_str_empty(VALUE str) { return RBOOL(RSTRING_LEN(str) == 0); }
返回一个根据 dst_encoding
转换编码后的 self
副本。默认情况下,如果 self
包含无效字节或 dst_encoding
中未定义的字符,则会引发异常;此行为可以通过编码选项修改;请参见下文。
无参数
-
如果
Encoding.default_internal
为nil
(默认值),则使用相同的编码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_encoding
和 src_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
相似,但将编码更改应用于 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); }
返回表示 obj 编码的 Encoding
对象。
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); }
返回 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
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; }
如果 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); }
将 self
的编码更改为 encoding
,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]
即使给定的encoding
对于self
无效(如上面的更改),也会进行更改
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; }
返回以零为基准的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]); }
返回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); }
返回self
的副本,其中所有出现的给定pattern
都被替换。
参见替换方法.
如果未给出replacement
和块,则返回一个Enumerator
.
相关:String#sub
, String#sub!
, String#gsub!
.
static VALUE rb_str_gsub(int argc, VALUE *argv, VALUE str) { return str_gsub(argc, argv, str, 0); }
对self
执行指定的子字符串替换;如果发生任何替换,则返回self
,否则返回nil
。
参见替换方法.
如果未给出replacement
和块,则返回一个Enumerator
.
相关:String#sub
, String#gsub
, String#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); }
返回self
的整数哈希值。该值基于self
的长度、内容和编码。
相关:Object#hash
.
static VALUE rb_str_hash_m(VALUE str) { st_index_t hval = rb_str_hash(str); return ST2FIX(hval); }
将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); }
如果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); }
返回给定参数的第一个匹配项的整数索引,如果未找到,则返回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; }
将给定的 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; }
返回 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; }
返回与 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; }
返回 self
的编码是否为 EUC-JP。
# File ext/nkf/lib/kconv.rb, line 264 def iseuc; Kconv.iseuc(self) end
返回 self
的编码是否为 ISO-2022-JP。
# File ext/nkf/lib/kconv.rb, line 276 def isjis; Kconv.isjis(self) end
返回 self
的编码是否为 Shift_JIS。
# File ext/nkf/lib/kconv.rb, line 270 def issjis; Kconv.issjis(self) end
返回 self
的编码是否为 UTF-8。
# File ext/nkf/lib/kconv.rb, line 282 def isutf8; Kconv.isutf8(self) end
返回 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)); }
根据给定的参数形成 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); }
返回 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#rjust
,String#center
。
static VALUE rb_str_ljust(int argc, VALUE *argv, VALUE str) { return rb_str_justify(argc, argv, str, 'l'); }
返回 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#rstrip
,String#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); }
与 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; }
根据 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; }
根据self
和pattern
是否匹配返回true
或false
。
注意:不会更新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); }
将self
的开头子字符串解释为八进制数字字符串(带可选符号),并返回相应的数字;如果不存在这样的开头子字符串,则返回零
'123'.oct # => 83 '-377'.oct # => -255 '0377non-numeric'.oct # => 255 'non-numeric'.oct # => 0
如果self
以0
开头,则会遵守基数指示符;请参阅Kernel#Integer
。
相关:String#hex
。
static VALUE rb_str_oct(VALUE str) { return rb_str_to_inum(str, -8, FALSE); }
返回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); }
返回self
的三个子字符串的数组。
将模式与self
匹配,从开头扫描。模式是
-
string_or_regexp
本身,如果它是Regexp
。 -
Regexp.quote(string_or_regexp)
,如果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#rpartition
,String#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)); }
将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; }
用other_string
的内容替换self
的内容
s = 'foo' # => "foo" s.replace('bar') # => "bar"
返回一个新的字符串,其中包含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; }
返回其字符反转后的 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; }
返回给定 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
(如果给出且非负)指定字符串中最大起始位置。
string to _end_ the search: '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; }
返回 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#ljust
,String#center
。
static VALUE rb_str_rjust(int argc, VALUE *argv, VALUE str) { return rb_str_justify(argc, argv, str, 'r'); }
返回self
的三个子字符串的数组。
将模式与 self
匹配,从末尾开始反向扫描。模式是
-
string_or_regexp
本身,如果它是Regexp
。 -
Regexp.quote(string_or_regexp)
,如果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#partition
,String#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)); }
返回接收者的副本,其中已删除尾随空格;请参阅 字符串中的空格
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#lstrip
,String#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); }
与 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; }
将模式与 self
进行匹配;模式是
-
string_or_regexp
本身,如果它是Regexp
。 -
Regexp.quote(string_or_regexp)
,如果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; }
返回 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; }
与 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; }
将以零为基准的 index
处的字节设置为 integer
;返回 integer
s = 'abcde' # => "abcde" s.setbyte(0, 98) # => 98 s # => "bbcde"
相关:String#getbyte
.
static 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; }
对 str
进行转义,以便它可以在 Bourne shell 命令行中安全使用。
有关详细信息,请参见 Shellwords.shellescape
。
# File lib/shellwords.rb, line 226 def shellescape Shellwords.escape(self) end
将 str
分割成一个标记数组,方式与 UNIX Bourne shell 相同。
有关详细信息,请参见 Shellwords.shellsplit
。
# File lib/shellwords.rb, line 215 def shellsplit Shellwords.split(self) end
移除并返回由参数指定的 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; }
返回一个 self
的子字符串数组,这些子字符串是通过在给定的字段分隔符 field_sep
的每个出现位置分割 self
而产生的。
当 field_sep
为 $;
时
-
如果
$;
为nil
(其默认值),则分割就像field_sep
被指定为空格字符一样(见下文)。 -
如果
$;
为字符串,则分割就像field_sep
被指定为该字符串一样(见下文)。
当 field_sep
为 ' '
且 limit
为 nil
时,分割发生在每个空白字符序列处
'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
为与 ' '
不同的字符串且 limit
为 nil
时,分割发生在 field_sep
的每个出现位置;不会返回尾部的空子字符串
'abracadabra'.split('ab') => ["", "racad", "ra"] 'aaabcdaaa'.split('a') => ["", "", "", "bcd"] ''.split('a') => [] '3.14159'.split('1') => ["3.", "4", "59"] '!@#$%^$&*($)_+'.split('$') # => ["!@#", "%^", "&*(", ")_+"] 'тест'.split('т') => ["", "ес"] 'こんにちは'.split('に') => ["こん", "ちは"]
当 field_sep
为 Regexp
且 limit
为 nil
时,分割发生在匹配项的每个出现位置;不会返回尾部的空子字符串
'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"]
如上所述,如果 limit
为 nil
,则不会返回尾部的空子字符串;如果 limit
为零,则也是如此
'aaabcdaaa'.split('a') => ["", "", "", "bcd"] 'aaabcdaaa'.split('a', 0) # => ["", "", "", "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
为 nil
相同,这意味着没有限制,并且包含尾部的空子字符串
'aaabcdaaa'.split('a', -1) # => ["", "", "", "bcd", "", "", ""]
如果给定一个代码块,则它将使用每个子字符串调用
'abc def ghi'.split(' ') {|substring| p substring }
输出
"abc" "def" "ghi"
相关:String#partition
,String#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; }
返回 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; }
类似于 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; }
返回 self
是否以任何给定的 string_or_regexp
开头。
将模式与 self
的开头匹配。对于每个给定的 string_or_regexp
,模式为
-
string_or_regexp
本身,如果它是Regexp
。 -
Regexp.quote(string_or_regexp)
,如果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; }
返回接收者的副本,其中删除了前导和尾随空格;请参阅 字符串中的空格
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#lstrip
,String#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); }
类似于 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; }
返回 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; }
返回 self
,其中仅替换了给定 pattern
的第一次出现(而不是所有出现)。
参见替换方法.
相关: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_name(str_enc), rb_enc_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; }
返回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"
空字符串的后继是一个新的空字符串
''.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); }
等效于 String#succ
,但就地修改self
;返回self
。
static VALUE rb_str_succ_bang(VALUE str) { rb_str_modify(str); str_succ(str); return str; }
返回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; }
返回一个字符串,其中包含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; }
将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; }
返回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)
如果字符串无法转换,则返回 Complex 零。
'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; }
返回将 str
中的开头字符解释为 BigDecimal
的结果。
require 'bigdecimal' require 'bigdecimal/util' "0.5".to_d # => 0.5e0 "123.45e1".to_d # => 0.12345e4 "45.67 degrees".to_d # => 0.4567e2
另请参见 Kernel.BigDecimal
。
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 72 def to_d BigDecimal.interpret_loosely(self) end
返回将 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)); }
返回将 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); }
返回将 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; }
如果 self
是 String,则返回 self
;如果 self
是 String 的子类,则返回 self
转换为 String 的结果。
static VALUE rb_str_to_s(VALUE str) { if (rb_obj_class(str) != rb_cString) { return str_duplicate(rb_cString, str); } return str; }
返回与 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"
将 self
转换为 EUC-JP。
# File ext/nkf/lib/kconv.rb, line 224 def toeuc; Kconv.toeuc(self) end
将 self
转换为 ISO-2022-JP。
# File ext/nkf/lib/kconv.rb, line 218 def tojis; Kconv.tojis(self) end
将 self
转换为区域设置编码。
# File ext/nkf/lib/kconv.rb, line 254 def tolocale; Kconv.tolocale(self) end
将self
转换为Shift_JIS
# File ext/nkf/lib/kconv.rb, line 230 def tosjis; Kconv.tosjis(self) end
将self
转换为UTF-16
# File ext/nkf/lib/kconv.rb, line 242 def toutf16; Kconv.toutf16(self) end
将self
转换为UTF-32
# File ext/nkf/lib/kconv.rb, line 248 def toutf32; Kconv.toutf32(self) end
将self
转换为UTF-8
# File ext/nkf/lib/kconv.rb, line 236 def toutf8; Kconv.toutf8(self) end
返回self
的副本,其中由字符串selector
指定的每个字符都被转换为字符串replacements
中的对应字符。对应关系是位置的
-
selector
指定的第一个字符的每次出现都被转换为replacements
中的第一个字符。 -
selector
指定的第二个字符的每次出现都被转换为replacements
中的第二个字符。 -
以此类推。
示例
'hello'.tr('el', 'ip') #=> "hippo"
如果replacements
比selector
短,它将隐式地用它自己的最后一个字符填充
'hello'.tr('aeiou', '-') # => "h-ll-" 'hello'.tr('aeiou', 'AA-') # => "hAll-"
参数selector
和replacements
必须是有效的字符选择器(参见字符选择器),并且可以使用其任何有效形式,包括否定、范围和转义
# 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; }
与String#tr
类似,但会修改self
。如果进行了任何更改,则返回self
,否则返回nil
。
static VALUE rb_str_tr_bang(VALUE str, VALUE src, VALUE repl) { return tr_trans(str, src, repl, 0); }
与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; }
与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); }
返回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#dump
(String#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 规范化的 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); }
与 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)); }
如果 self
处于给定的 form
的 Unicode 规范化形式,则返回 true
,否则返回 false
。form
必须是 :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); }
从 self
中提取数据,形成成为新数组元素的对象;返回该数组。参见 Packed Data。
# File pack.rb, line 19 def unpack(fmt, offset: 0) Primitive.pack_unpack(fmt, offset) end
与 String#unpack
相似,但只解包并返回第一个提取的对象。参见 Packed Data。
# File pack.rb, line 28 def unpack1(fmt, offset: 0) Primitive.pack_unpack1(fmt, offset) end
返回一个包含 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; }
将 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; }
如果给定代码块,则使用每次调用 String#succ
返回的每个字符串值调用代码块;第一个值是 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 }
如果没有给定代码块,则返回一个新的枚举器
'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); }
如果 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); }