非常教程

Ruby 2.4参考手册

Regexp

Regexp

父类:对象

Regexp拥有一个正则表达式,用于匹配字符串的模式。正则表达式是使用/.../%r{...}文字以及Regexp::new构造函数创建的。

正则表达式(regexp_s)是描述字符串内容的模式。它们用于测试字符串是否包含给定模式,或者提取匹配的部分。它们是用/_pat/%r{pat}文字或Regexp.new构造函数创建的。

正则表达式通常用正斜杠(/)分隔。例如:

/hay/ =~ 'haystack'   #=> 0
/y/.match('haystack') #=> #<MatchData "y">

如果一个字符串包含它被认为匹配的模式。一个文字串匹配它自己。

这里'haystack'不包含模式'针',所以它不匹配:

/needle/.match('haystack') #=> nil

这里'haystack'包含模式'hay',所以它匹配:

/hay/.match('haystack')    #=> #<MatchData "hay">

具体来说,/st/要求字符串包含字母s后跟字母t,所以它也与干草堆相匹配。

=~ and #match

模式匹配可以通过使用=~运算符或#match方法来实现。

=~ operator

=~是Ruby的基本模式匹配运算符。当一个操作数是一个正则表达式而另一个是一个字符串时,则正则表达式被用作模式来匹配字符串。(这个操作符等价地由Regexp和String定义,所以String和Regexp的顺序无关紧要,其他类可能有不同的实现=~。)如果找到匹配,操作符返回字符串中第一个匹配的索引,否则返回nil

/hay/ =~ 'haystack'   #=> 0
'haystack' =~ /hay/   #=> 0
/a/   =~ 'haystack'   #=> 1
/u/   =~ 'haystack'   #=> nil

使用=~带有String和Regexp的运算符,$~在成功匹配后设置全局变量。$~拥有一个MatchData对象。:: last_match等价于$~

#match method

匹配方法返回一个MatchData对象:

/st/.match('haystack')   #=> #<MatchData "st">

元字符和转义

以下是元字符 ()[]{}.?+*。出现在模式中时,它们有特定的含义。要从字面上匹配它们,它们必须被反斜线转义。匹配反斜杠字面上的反斜杠 - 转义:\\\

/1 \+ 2 = 3\?/.match('Does 1 + 2 = 3?') #=> #<MatchData "1 + 2 = 3?">

模式表现得像双引号字符串,因此可以包含相同的反斜杠转义符。

/\s\u{6771 4eac 90fd}/.match("Go to 東京都")
    #=> #<MatchData " 東京都">

任意的Ruby表达式可以嵌入到#{...}构造的模式中。

place = "東京都"
/#{place}/.match("Go to 東京都")
    #=> #<MatchData "東京都">

Character Classes

字符类被分隔用方括号([]可能出现在匹配该点)和列表的字符。/[ab]/意味着一个b,相对于/ab/这意味着一个随后b

/W[aeiou]rd/.match("Word") #=> #<MatchData "Word">

在字符类中,连字符(-)是一个表示包含字符范围的元字符。[abcd]相当于[a-d]。一个范围可以跟着另一个范围,所以[abcdwxyz]相当于[a-dw-z]。范围或单个字符在字符类中出现的顺序是不相关的。

/[0-9a-f]/.match('9f') #=> #<MatchData "9">
/[9f]/.match('9f')     #=> #<MatchData "9">

如果字符类的第一个字符是caret(^),则该类将被反转:它会匹配名称之外的任何字符。

/[^a-eg-z]/.match('f') #=> #<MatchData "f">

一个字符类可能包含另一个字符类。本身并没有用,因为[a-z[0-9]]描述了与之相同的集合[a-z0-9]。但是,字符类还支持&&对其参数执行集合交集的运算符。这两者可以结合如下:

/[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))

这相当于:

/[abh-w]/

以下元字符的行为类似于字符类:

  • /./ - 除换行符外的任何字符。
  • /./m- 任何字符(m修饰符启用多行模式)
  • /\w/- 一个字符([a-zA-Z0-9_]
  • /\W/- 一个非单词字符([^a-zA-Z0-9_])。请看看错误#4044,如果使用/\W//i修改。
  • /\d/- 一个数字字符([0-9]
  • /\D/- 非数字字符([^0-9]
  • /\h/- 一个十六进制字符([0-9a-fA-F]
  • /\H/- 一个非十六进制字符([^0-9a-fA-F]
  • /\s/ - 空格字符: /[ \t\r\n\f\v]/
  • /\S/ - 非空白字符: /[^ \t\r\n\f\v]/

POSIX 括号表达式也与字符类相似。它们为上述提供了一种便携式替代方案,而且还包含非ASCII字符。例如,/\d/只匹配ASCII十进制数字(0-9); 而/[[:digit:]]/匹配Unicode Nd类别中的任何字符。

  • /[[:alnum:]]/ - 字母和数字字符
  • /[[:alpha:]]/ - 字母字符
  • /[[:blank:]]/ - 空间或标签
  • /[[:cntrl:]]/ - 控制字符
  • /[[:digit:]]/ - 数字
  • /[[:graph:]]/ - 非空白字符(不包括空格,控制字符和类似字符)
  • /[[:lower:]]/ - 小写字母字符
  • /[[:print:]]/ - 如:图:,但包含空格字符
  • /[[:punct:]]/ - 标点符号
  • /[[:space:]]/- 空格字符([:blank:],换行符,回车等)
  • /[[:upper:]]/ - 大写字母
  • /[[:xdigit:]]/ - 数字允许以十六进制数字(即0-9a-fA-F)

Ruby还支持以下非POSIX字符类:

  • /[[:word:]]/- 以下Unicode常规类别之一的字符LetterMarkNumberConnector_Punctuation
  • /[[:ascii:]]/ - ASCII字符集中的字符

Repetition

到目前为止描述的结构符合单个字符。它们可以跟随一个重复元字符来指定它们需要发生的次数。这种元字符称为量词

  • * - 零次或多次
  • + - 一次或多次
  • ? - 零次或一次(可选)
  • {n} - 恰好n
  • {n,} - n次或更多次
  • {,m} - m或更少
  • {n,m}- 至少n次,最多m

至少一个大写字符('H'),至少一个小写字符('e'),两个'l'字符,然后一个'o':

"Hello".match(/[[:upper:]]+[[:lower:]]+l{2}o/) #=> #<MatchData "Hello">

默认情况下,重复是贪婪的:尽可能多地匹配,同时仍然允许总体匹配成功。相比之下, 延迟匹配使得整体成功所需的最少量的匹配成为可能。一个贪婪的元字符可以通过跟随它而变得很懒?

这两个模式都与字符串匹配。第一个使用贪婪量词,所以'。+'匹配'<a> <b>'; 第二个使用一个懒惰的量词,所以'。+?' 匹配“<a>”:

/<.+>/.match("<a><b>")  #=> #<MatchData "<a><b>">
/<.+?>/.match("<a><b>") #=> #<MatchData "<a>">

量词后跟+匹配占有性:一旦匹配不走回头路。他们表现得像贪婪的量词,但是如果匹配,他们拒绝“放弃”他们的比赛,即使这会危及整体比赛。

捕获

圆括号可用于捕获。由第n组括号括起来的文本 随后可以用n来表示。在模式内使用 反向引用 \n ; 在模式外使用 MatchData[n]

'at'由第一组括号捕获,然后在后面提及\1

/[csh](..) [csh]\1 in/.match("The cat sat in the hat")
    #=> #<MatchData "cat sat in" 1:"at">

#match返回一个MatchData对象,该对象使用[]方法使捕获的文本可用:

/[csh](..) [csh]\1 in/.match("The cat sat in the hat")[1] #=> 'at'

当使用(?<名称>)(?'名称')结构进行定义时,捕获组可以按名称引用。

/\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")
    #=> #<MatchData "$3.67" dollars:"3" cents:"67">
/\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")[:dollars] #=> "3"

命名组可以用\k<名称反向引用>,其中name是组名称。

/(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
    #=> #<MatchData "ototo" vowel:"o">

注意:正则表达式不能同时使用命名的反向引用和编号的反向引用。

当命名的捕获组与表达式和=~操作符左侧的文字正则表达式一起使用时,捕获的文本也会被分配给具有相应名称的局部变量。

/\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
dollars #=> "3"

分组

还括号它们包围的条款,允许它们被作为一个量化的原子整体。

下面的模式匹配一​​个元音后跟两个单词字符:

/ [aeiou] \ w {2} /。match(“Caenorhabditis elegans”)#=>#<MatchData“aen”>

而下面的模式匹配一​​个元音后跟一个单词字符,两次,即[aeiou]\w[aeiou]\w:'enor'。

/([aeiou] \ w){2} /。match(“Caenorhabditis elegans”)
     #=>#<MatchData“enor”1:“or”>

(?:... )构造提供分组而不捕获。也就是说,它将它包含的术语组合到一个原子整体中,而不创建反向引用。这样可以降低可读性,有利于性能。

第一组圆括号包含'n'和第二个'ti'。后面提到的第二组是反向引用 \2

/ I(n)ves(ti)ga \ 2ons /。match(“Investigations”)
     #=>#<MatchData“Investigations”1:“n”2:“ti”>

现在第一组圆括号用'?:'进行非捕获,所以它仍然匹配'n',但不创建反向引用。因此,反向引用\1现在指的是'ti'。

/ I(?:n)ves(ti)ga \ 1ons /。match(“Investigations”)
     #=>#<MatchData“Investigations”1:“ti”>

原子分组

分组可以用 pat拍成原子。这会导致子表达式pat独立于表达式的其余部分进行匹配,因此它匹配的内容会在匹配的其余部分变得固定,除非整个子表达式必须放弃并随后重新访问。通过这种方式,pat被视为一个不可分割的整体。原子分组通常用于优化模式,以防止正则表达式引擎不必要地回溯。(?>)

"图案中的下面相匹配的字符串的第一个字符,然后.*匹配报价“。这会导致整个匹配失败,所以匹配的文本.*会被一个位置回溯,从而使字符串的最后一个字符可以匹配"

/".*"/。match('“Quote”')      #=>#<MatchData“\”Quote \“”>

如果.*以原子方式分组,则拒绝回溯 引用“,尽管这意味着整体匹配失败

/I(?:n)ves(ti)ga\1ons/.match("Investigations")
    #=> #<MatchData "Investigations" 1:"ti">

子表达式调用

\g<>语法命名前面的子表达式匹配的名称,它可以是一组名称或号码,再次。这不同于反向引用,因为它重新执行组而不是简单地重新匹配相同的文本。

此模式匹配字符并将其分配给 paren组,尝试再次调用该paren 子表达式但失败,然后匹配文字

/\A(?<paren>\(\g<paren>*\))*\z/ =~ '()'

/\A(?<paren>\(\g<paren>*\))*\z/ =~ '(())' #=> 0
# ^1
#      ^2
#           ^3
#                 ^4
#      ^5
#           ^6
#                      ^7
#                       ^8
#                       ^9
#                           ^10
  1. 匹配字符串的开头,即在第一个字符之前。

2. 进入名为的已命名捕获组 paren

3. 匹配一个文字,字符串中的第一个字符

4. paren再次调用该组,即递归回到第二步

5. 重新进入该paren

6. 匹配一个文字,字符串中的第二个字符

7. 尝试paren第三次调用,但失败,因为这样做会阻止整体成功的匹配

8. 匹配文字,字符串中的第三个字符。标记第二次递归调用的结束

9. 匹配文字,即字符串中的第四个字符

10. 匹配string

Alternation

结尾垂直栏metacharacter(|)将两个表达式组合成一个匹配任一表达式的表达式。每个表达式都是一种替代方式

/ \ w(和| or)\ w /。match(“Feliformia”)#=>#<MatchData“form”1:“or”> 
/ \ w(and | or)\ w /。match(“furandi”)     #=>#<MatchData“randi”1:“and”> 
/ \ w(and | or)\ w /。match(“dissemblance”)#=> nil

字符属性¶ ↑

\p{}构造将字符与命名属性匹配,就像POSIX括号类一样。

  • /\p{Alnum}/ - 字母和数字字符
  • /\p{Alpha}/ - 字母字符
  • /\p{Blank}/ - 空间或标签
  • /\p{Cntrl}/ - 控制字符
  • /\p{Digit}/ - 数字
  • /\p{Graph}/ - 非空白字符(不包括空格,控制字符和类似字符)
  • /\p{Lower}/ - 小写字母字符
  • /\p{Print}/- 如\p{Graph},但包括空格字符
  • /\p{Punct}/ - 标点符号
  • /\p{Space}/- 空格字符([:blank:],换行符,回车等)
  • /\p{Upper}/ - 大写字母
  • /\p{XDigit}/ - 数字允许以十六进制数字(即0-9a-fA-F)
  • /\p{Word}/- 以下Unicode常规类别之一的成员LetterMarkNumberConnector_Punctuation
  • /\p{ASCII}/ - ASCII字符集中的字符
  • /\p{Any}/ - 任何Unicode字符(包括未分配的字符)
  • /\p{Assigned}/- 指定的字符Unicode字符的常规类别值也可以与\p{Ab匹配,}其中Ab是类别的缩写,如下所述:
  • /\p{L}/ - 'Letter'
  • /\p{Ll}/ - 'Letter: Lowercase'
  • /\p{Lm}/ - 'Letter: Mark'
  • /\p{Lo}/ - 'Letter: Other'
  • /\p{Lt}/ - 'Letter: Titlecase'
  • /\p{Lu}/ - 'Letter: Uppercase
  • /\p{Lo}/ - 'Letter: Other'
  • /\p{M}/ - 'Mark'
  • /\p{Mn}/ - 'Mark: Nonspacing'
  • /\p{Mc}/ - 'Mark: Spacing Combining'
  • /\p{Me}/ - 'Mark: Enclosing'
  • /\p{N}/ - 'Number'
  • /\p{Nd}/ - 'Number: Decimal Digit'
  • /\p{Nl}/ - 'Number: Letter'
  • /\p{No}/ - 'Number: Other'
  • /\p{P}/ - 'Punctuation'
  • /\p{Pc}/ - 'Punctuation: Connector'
  • /\p{Pd}/ - 'Punctuation: Dash'
  • /\p{Ps}/ - 'Punctuation: Open'
  • /\p{Pe}/ - 'Punctuation: Close'
  • /\p{Pi}/ - 'Punctuation: Initial Quote'
  • /\p{Pf}/ - 'Punctuation: Final Quote'
  • /\p{Po}/ - 'Punctuation: Other'
  • /\p{S}/ - 'Symbol'
  • /\p{Sm}/ - 'Symbol: Math'
  • /\p{Sc}/ - 'Symbol: Currency'
  • /\p{Sc}/ - 'Symbol: Currency'
  • /\p{Sk}/ - 'Symbol: Modifier'
  • /\p{So}/ - 'Symbol: Other'
  • /\p{Z}/ - 'Separator'
  • /\p{Zs}/ - 'Separator: Space'
  • /\p{Zl}/ - 'Separator: Line'
  • /\p{Zp}/ - 'Separator: Paragraph'
  • /\p{C}/ - 'Other'
  • /\p{Cc}/ - 'Other: Control'
  • /\p{Cf}/ - 'Other: Format'
  • /\p{Cn}/ - 'Other: Not Assigned'
  • /\p{Co}/ - 'Other: Private Use'
  • /\p{Cs}/ - 'Other: Surrogate'

最后,\p{}匹配一个字符的Unicode 脚本。下面的脚本支持:阿拉伯语亚美尼亚巴厘孟加拉语汉语拼音盲文布吉文布迪文Canadian_Aboriginal卡里亚切诺基通用科普特人楔形文字塞浦路斯西里尔文犹他州梵文埃塞俄比亚格鲁吉亚格拉哥里哥特式希腊语古吉拉特语旁遮普文朝鲜文哈努诺文希伯来文平假名继承埃纳德语片假名KAYAH_LI卡罗须提语高棉老挝拉丁语雷布查林布Linear_B利西亚吕底亚马拉雅拉姆语蒙古缅甸NEW_TAI_LUE西非书面语言欧甘文OL_CHIKIOld_ItalicOld_Persian奥里雅语奥斯曼亚语Phags_Pa腓尼基拉让符文索拉什特拉萧伯纳僧伽罗人Syloti_Nagri叙利亚菲律宾语塔格巴努亚文Tai_Le泰米尔语, Telugu, Thaana, Thai, Tibetan, Tifinagh, Ugaritic, Vai, and Yi.

Unicode代码点U + 06E9被命名为“ARABIC PLACE OF SAJDAH”并属于阿拉伯语脚本:

/\p{Arabic}/.match("\u06E9") #=> #<MatchData "\u06E9">

所有的字符属性都可以通过在名称前加上插入符(^)来反转。

字母'A'不在Unicode Ll(Letter;小写字母)类别中,因此该匹配成功:

/\p{^Ll}/.match("A") #=> #<MatchData "A">

Anchors

锚点是元字符,匹配字符之间的零宽度位置,匹配锚定到特定位置。

  • ^ - 匹配行首
  • $ - 匹配行尾
  • \A - 匹配字符串的开头。
  • \Z - 匹配字符串的结尾。如果字符串以换行符结束,则它在换行符之前匹配
  • \z - 匹配字符串的结尾
  • \G - 匹配第一个匹配位置:

在像String#gsub和的方法中String#scan,它在每次迭代中都会改变。它最初匹配主题的开始,并且在每个后续迭代中它匹配最后匹配完成的地方。

" a b c".gsub(/ /, '_') #=> "____a_b_c" " a b c".gsub(/\G /, '_') #=> "____a b c"

在类似的方法Regexp#matchString#match称取(可选的)偏移量,它匹配于搜索的开始位置。

"hello, world".match(/,/, 3) #=> #<MatchData ","> "hello, world".match(/\G,/, 3) #=> nil

  • \b - 在括号外匹配单词边界; 当括号内的退格(0x08)
  • \B - 匹配非单词边界
  • (?=pat) - 积极的lookahead断言:确保以下字符匹配pat,但不包括匹配文本中的那些字符
  • (?!pat) - 负向前瞻断言:确保以下字符不匹配pat,但不包括匹配文本中的那些字符
  • (?<=pat) - 积极的lookbehind断言:确保前面的字符匹配pat,但不包括匹配文本中的那些字符
  • (?<!pat) - 否定后置断言:确保前面的字符不匹配pat,但不包括匹配文本中的那些字符

如果一个模式没有锚定,它可以从字符串中的任何一点开始:

/real/.match("surrealist") #=> #<MatchData "real">

将模式锚定到字符串的开头会强制匹配从那里开始。'真'不会出现在字符串的开头,所以现在匹配失败:

/\Areal/.match("surrealist") #=> nil

下面的匹配失败,因为尽管'请求'包含'和',模式不会出现在单词边界。

/\band/.match("Demand")

而在下面的例子中,'和'已经锚定到一个非单词边界,所以不是匹配第一个'和'而是匹配来自'demand'的第四个字母:

/\Band.+/.match("Supply and demand curve") #=> #<MatchData "and curve">

下面的模式使用积极lookahead和积极lookbehind匹配出现在标签中的文本,而不包含匹配中的标签:

/(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the <b>bold</b>")
    #=> #<MatchData "bold">

Options

正则表达式的结束分隔符后面可以跟一个或多个单字母选项,用于控制模式如何匹配。

  • /pat/i - 忽略大小写
  • /pat/m - 将一个换行符视为一个匹配的字符 .
  • /pat/x - 忽略模式中的空格和注释
  • /pat/o- #{}只进行一次插值

imx也可以在与所述子表达式级别应用(?-)构建体,其使得选项,并禁用选项关闭用于由括号包围的表达。

/a(?i:b)c/.match('aBc') #=> #<MatchData "aBc">
/a(?i:b)c/.match('abc') #=> #<MatchData "abc">

选项也可以用于Regexp.new

Regexp.new("abc", Regexp::IGNORECASE)                     #=> /abc/i
Regexp.new("abc", Regexp::MULTILINE)                      #=> /abc/m
Regexp.new("abc # Comment", Regexp::EXTENDED)             #=> /abc # Comment/x
Regexp.new("abc", Regexp::IGNORECASE | Regexp::MULTILINE) #=> /abc/mi

Free-Spacing Mode and Comments

如上所述,该x选项启用自由间隔模式。模式内的文字空白被忽略,并且octothorpe(#)字符在该行的末尾引入注释。这允许模式的组件以更可读的方式进行组织。

与任意小数位数匹配的人为模式:

float_pat = /\A
    [[:digit:]]+ # 1 or more digits before the decimal point
    (\.          # Decimal point
        [[:digit:]]+ # 1 or more digits after the decimal point
    )? # The decimal point and following digits are optional
\Z/x
float_pat.match('3.14') #=> #<MatchData "3.14" 1:".14">

有许多匹配空白的策略:

  • 使用诸如\s或的模式\p{Space}
  • 使用诸如空格之类的空格\,即以反斜杠开头的空格。
  • 使用诸如[ ].Comments之类的字符类可以通过注释构造包含在非x模式中,其中注释是由正则表达式引擎忽略的任意文本。正则表达式文本中的注释不能包含未转义的终止符字符.EncodingRegular表达式假定使用源编码。这可以用以下修饰符之一来覆盖。(?#)
  • /pat/u - UTF-8
  • /pat/e - EUC-JP
  • /pat/s - Windows-31J
  • /pat/n - ASCII-8BITA

一个正则表达式可以与一个字符串匹配,当它们共享一个编码时,或者正则表达式的编码是US-ASCII并且该字符串的编码与ASCII兼容时。

如果试图在不兼容的编码之间进行匹配, Encoding::CompatibilityError则会引发异常。

所述Regexp#fixed_encoding?谓词表示正则表达式是否具有固定编码,即一个与ASCII不相容。正则表达式的编码可以通过提供Regexp::FIXEDENCODING以下参数的第二个参数 来显式修复 Regexp.new

r = Regexp.new("a".force_encoding("iso-8859-1"),Regexp::FIXEDENCODING)
r =~ "a\u3042"
   # raises Encoding::CompatibilityError: incompatible encoding regexp match
   #         (ISO-8859-1 regexp with UTF-8 string)
  • $~ 相当于:: last_match;
  • $& 包含完整的匹配文本;
  • $` 包含匹配前的字符串;
  • $' 包含匹配后的字符串;
  • $1$2等等包含与第一,第二等捕获组相匹配的文本;
  • $+ 包含最后一个捕获组。

例:

m = /s(\w{2}).*(c)/.match('haystack') #=> #<MatchData "stac" 1:"ta" 2:"c">
$~                                    #=> #<MatchData "stac" 1:"ta" 2:"c">
Regexp.last_match                     #=> #<MatchData "stac" 1:"ta" 2:"c">

$&      #=> "stac"
        # same as m[0]
$`      #=> "hay"
        # same as m.pre_match
$'      #=> "k"
        # same as m.post_match
$1      #=> "ta"
        # same as m[1]
$2      #=> "c"
        # same as m[2]
$3      #=> nil
        # no third group in pattern
$+      #=> "c"
        # same as m[-1]

这些全局变量是线程局部变量和方法局部变量。

Performance

构建体的某些病态组合可能导致糟糕的表现。

考虑一个25个a_s,一个_d,4个a_s和一个_c的字符串。

s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
#=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"

以下模式可以像您期望的那样立即匹配:

/(b|a)/ =~ s #=> 0
/(b|a+)/ =~ s #=> 0
/(b|a+)*/ =~ s #=> 0

但是,以下模式花费的时间明显较长:

/(b|a+)*c/ =~ s #=> 26

发生这种情况的原因是,正则表达式中的原子可以通过立即+和封闭来进行量化*,无需区分哪个字符受控于任何特定字符。结果产生的非确定性会产生超线性性能。(请参阅Mastering Regular Expressions(第三版),第222页,由Jeffery Friedl进行深入分析)。这种特殊情况可以通过使用原子分组来解决,这可以防止不必要的回溯:

(start = Time.now) && /(b|a+)*c/ =~ s && (Time.now - start)
   #=> 24.702736882
(start = Time.now) && /(?>b|a+)*c/ =~ s && (Time.now - start)
   #=> 0.000166571

下面的例子代表了一个类似的例子,这个例子大约需要60秒来执行:

匹配29个_a_s的字符串与29个可选的_a_s的模式,然后是29个必需的_a_s:

Regexp.new('a?' * 29 + 'a' * 29) =~ 'a' * 29

29个可选的_a_s匹配字符串,但是这阻止了匹配后面的29个必须的_a_s。Ruby必须重复回溯,以便满足尽可能多的可选匹配,同时仍然匹配必需的29.我们很清楚,没有任何可选匹配可以成功,但是这一事实很遗憾地让Ruby无法回避。

提高性能的最佳方法是显着减少所需的回溯数量。对于这种情况,不是单独匹配29个可选的a_s,而是可以使用_a {0,29}一次性匹配一系列可选的_a_s

Regexp.new('a{0,29}' + 'a' * 29) =~ 'a' * 29

Constants

EXTENDED

see #options and ::new

FIXEDENCODING

see #options and ::new

IGNORECASE

see #options and ::new

MULTILINE

see #options and ::new

NOENCODING

see #options and ::new

Public Class Methods

compile(*args)

Alias for Regexp.new

escape(str) → string Show source

转义任何在正则表达式中具有特殊含义的字符。返回一个新的转义字符串,如果没有字符转义,则返回self。对于任何字符串,将是真实的。Regexp.new(Regexp.escape(str))=~str

Regexp.escape('\*?{}.')   #=> \\\*\?\{\}\.
static VALUE
rb_reg_s_quote(VALUE c, VALUE str)
{
    return rb_reg_quote(reg_operand(str, TRUE));
}

json_create(object) Show source

通过构建具有源代码s(Regexp或String)和选项o序列化的新Regexp对象来反序列化JSON字符串to_json

# File ext/json/lib/json/add/regexp.rb, line 11
def self.json_create(object)
  new(object['s'], object['o'])
end

last_match → matchdata Show source

last_match(n) → str

第一种形式返回上次成功模式匹配生成的MatchData对象。相当于读取特殊的全局变量$~(有关详细信息,请参阅Regexp中的特殊全局变量)。

第二种形式返回此MatchData对象中的n个字段。_n可以是一个字符串或符号来引用一个命名的捕获。

请注意:: :: last_match对于模式匹配的方法的线程和方法范围是本地的。

/c(.)t/ =~ 'cat'        #=> 0
Regexp.last_match       #=> #<MatchData "cat" 1:"a">
Regexp.last_match(0)    #=> "cat"
Regexp.last_match(1)    #=> "a"
Regexp.last_match(2)    #=> nil

/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ "var = val"
Regexp.last_match       #=> #<MatchData "var = val" lhs:"var" rhs:"val">
Regexp.last_match(:lhs) #=> "var"
Regexp.last_match(:rhs) #=> "val"
static VALUE
rb_reg_s_last_match(int argc, VALUE *argv)
{
    VALUE nth;

    if (argc > 0 && rb_scan_args(argc, argv, "01", &nth) == 1) {
        VALUE match = rb_backref_get();
        int n;
        if (NIL_P(match)) return Qnil;
        n = match_backref_number(match, nth);
        return rb_reg_nth_match(n, match);
    }
    return match_getter();
}

new(string, options) → regexp Show source

new(regexp) → regexp

compile(string, options) → regexp

compile(regexp) → regexp

构造一个新的正则表达式pattern,它可以是一个String或一个Regexp(在这种情况下regexp的选项被传播),并且新的选项可能没有被指定(从Ruby 1.8开始的变化)。

如果options是一个Integer,它应该是一个或多个常量Regexp :: EXTENDED,Regexp :: IGNORECASE和Regexp :: MULTILINE,或者 -ed在一起。否则,如果options不是nil或,则正false则表达式将不区分大小写。

r1 = Regexp.new('^a-z+:\s+\w+') #=> /^a-z+:\s+\w+/
r2 = Regexp.new('cat', true)     #=> /cat/i
r3 = Regexp.new(r2)              #=> /cat/i
r4 = Regexp.new('dog', Regexp::EXTENDED | Regexp::IGNORECASE) #=> /dog/ix
static VALUE
rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
{
    int flags = 0;
    VALUE str;
    rb_encoding *enc = 0;

    rb_check_arity(argc, 1, 3);
    if (RB_TYPE_P(argv[0], T_REGEXP)) {
        VALUE re = argv[0];

        if (argc > 1) {
            rb_warn("flags ignored");
        }
        rb_reg_check(re);
        flags = rb_reg_options(re);
        str = RREGEXP_SRC(re);
    }
    else {
        if (argc >= 2) {
            if (FIXNUM_P(argv[1])) flags = FIX2INT(argv[1]);
            else if (RTEST(argv[1])) flags = ONIG_OPTION_IGNORECASE;
        }
        if (argc == 3 && !NIL_P(argv[2])) {
            char *kcode = StringValuePtr(argv[2]);
            if (kcode[0] == 'n' || kcode[0] == 'N') {
                enc = rb_ascii8bit_encoding();
                flags |= ARG_ENCODING_NONE;
            }
            else {
                rb_warn("encoding option is ignored - %s", kcode);
            }
        }
        str = StringValue(argv[0]);
    }
    if (enc && rb_enc_get(str) != enc)
        rb_reg_init_str_enc(self, str, enc, flags);
    else
        rb_reg_init_str(self, str, flags);
    return self;
}

quote(str) → string Show source

转义任何在正则表达式中具有特殊含义的字符。返回一个新的转义字符串,如果没有字符转义,则返回self。对于任何字符串,将是真实的。Regexp.new(Regexp.escape(str))=~str

Regexp.escape('\*?{}.')   #=> \\\*\?\{\}\.
static VALUE
rb_reg_s_quote(VALUE c, VALUE str)
{
    return rb_reg_quote(reg_operand(str, TRUE));
}

try_convert(obj) → re or nil Show source

尝试使用to_regexp方法将obj转换为Regexp。如果因任何原因无法转换obj,则返回转换的正则表达式或零。

Regexp.try_convert(/re/)         #=> /re/
Regexp.try_convert("re")         #=> nil

o = Object.new
Regexp.try_convert(o)            #=> nil
def o.to_regexp() /foo/ end
Regexp.try_convert(o)            #=> /foo/
static VALUE
rb_reg_s_try_convert(VALUE dummy, VALUE re)
{
    return rb_check_regexp_type(re);
}

union(pat1, pat2, ...) → new_regexp Show source

union(pats_ary) → new_regexp

返回Regexp给定pattern_s/(?!)/的并集的对象,即匹配其任何部分。_pattern_s可以是Regexp对象,在这种情况下,它们的选项将被保留,或者字符串。如果没有给出模式,则返回。如果任何给定的_pattern包含捕获,则行为是未指定的

Regexp.union                         #=> /(?!)/
Regexp.union("penzance")             #=> /penzance/
Regexp.union("a+b*c")                #=> /a\+b\*c/
Regexp.union("skiing", "sledding")   #=> /skiing|sledding/
Regexp.union(["skiing", "sledding"]) #=> /skiing|sledding/
Regexp.union(/dogs/, /cats/i)        #=> /(?-mix:dogs)|(?i-mx:cats)/

注意::: union的参数将尝试通过to_regexp转换为正则表达式字面值。

static VALUE
rb_reg_s_union_m(VALUE self, VALUE args)
{
    VALUE v;
    if (RARRAY_LEN(args) == 1 &&
        !NIL_P(v = rb_check_array_type(rb_ary_entry(args, 0)))) {
        return rb_reg_s_union(self, v);
    }
    return rb_reg_s_union(self, args);
}

公共实例方法

rxp == other_rxp → true or false Show source

平等 - 如果它们的模式相同,则两个正则表达式相等,它们具有相同的字符集代码,并且它们的casefold?值相同。

/abc/  == /abc/x   #=> false
/abc/  == /abc/i   #=> false
/abc/  == /abc/u   #=> false
/abc/u == /abc/n   #=> false
static VALUE
rb_reg_equal(VALUE re1, VALUE re2)
{
    if (re1 == re2) return Qtrue;
    if (!RB_TYPE_P(re2, T_REGEXP)) return Qfalse;
    rb_reg_check(re1); rb_reg_check(re2);
    if (FL_TEST(re1, KCODE_FIXED) != FL_TEST(re2, KCODE_FIXED)) return Qfalse;
    if (RREGEXP_PTR(re1)->options != RREGEXP_PTR(re2)->options) return Qfalse;
    if (RREGEXP_SRC_LEN(re1) != RREGEXP_SRC_LEN(re2)) return Qfalse;
    if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse;
    if (memcmp(RREGEXP_SRC_PTR(re1), RREGEXP_SRC_PTR(re2), RREGEXP_SRC_LEN(re1)) == 0) {
        return Qtrue;
    }
    return Qfalse;
}

rxp === str → true or false Show source

案例平等 - 用于案例陈述。

a = "HELLO"
case a
when /^[a-z]*$/; print "Lower case\n"
when /^[A-Z]*$/; print "Upper case\n"
else;            print "Mixed case\n"
end
#=> "Upper case"

在使用===运算符的正则表达式之后,可以使用字符串进行比较。

/^[a-z]*$/ === "HELLO" #=> false
/^[A-Z]*$/ === "HELLO" #=> true
VALUE
rb_reg_eqq(VALUE re, VALUE str)
{
    long start;

    str = reg_operand(str, FALSE);
    if (NIL_P(str)) {
        rb_backref_set(Qnil);
        return Qfalse;
    }
    start = rb_reg_search(re, str, 0, 0);
    if (start < 0) {
        return Qfalse;
    }
    return Qtrue;
}

rxp =~ str → integer or nil Show source

Match—Matches rxp against str.

/at/ =~ "input data"   #=> 7
/ax/ =~ "input data"   #=> nil

如果=~与带有命名捕获的正则表达式文字一起使用,捕获的字符串(或无)将被分配给由捕获名称命名的局部变量。

/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ "  x = y  "
p lhs    #=> "x"
p rhs    #=> "y"

如果不匹配,则为变量分配nil。

/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ "  x = "
p lhs    #=> nil
p rhs    #=> nil

这个任务是在Ruby解析器中实现的。解析器检测到赋值的'regexp-literal =〜expression'。正则表达式必须是没有插值的文字,并放置在左侧。

如果正则表达式不是字面值,则不会发生赋值。

re = /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
re =~ "  x = y  "
p lhs    # undefined local variable
p rhs    # undefined local variable

正则表达式插值#{}也会禁用分配。

rhs_pat = /(?<rhs>\w+)/
/(?<lhs>\w+)\s*=\s*#{rhs_pat}/ =~ "x = y"
p lhs    # undefined local variable

如果正则表达式位于右侧,则不会发生分配。

"  x = y  " =~ /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
p lhs, rhs # undefined local variable
VALUE
rb_reg_match(VALUE re, VALUE str)
{
    long pos = reg_match_pos(re, &str, 0);
    if (pos < 0) return Qnil;
    pos = rb_str_sublen(str, pos);
    return LONG2FIX(pos);
}

as_json(*) Show source

返回一个散列,它将变成一个JSON对象并表示这个对象。

# File ext/json/lib/json/add/regexp.rb, line 17
def as_json(*)
  {
    JSON.create_id => self.class.name,
    'o'            => options,
    's'            => source,
  }
end

casefold? → true or false Show source

返回不区分大小写的标志的值。

/a/.casefold?           #=> false
/a/i.casefold?          #=> true
/(?i:a)/.casefold?      #=> false
static VALUE
rb_reg_casefold_p(VALUE re)
{
    rb_reg_check(re);
    if (RREGEXP_PTR(re)->options & ONIG_OPTION_IGNORECASE) return Qtrue;
    return Qfalse;
}

encoding → encoding Show source

返回表示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);
}

eql?(other_rxp) → true or false Show source

平等 - 如果它们的模式相同,则两个正则表达式相等,它们具有相同的字符集代码,并且它们的casefold?值相同。

/abc/  == /abc/x   #=> false
/abc/  == /abc/i   #=> false
/abc/  == /abc/u   #=> false
/abc/u == /abc/n   #=> false
static VALUE
rb_reg_equal(VALUE re1, VALUE re2)
{
    if (re1 == re2) return Qtrue;
    if (!RB_TYPE_P(re2, T_REGEXP)) return Qfalse;
    rb_reg_check(re1); rb_reg_check(re2);
    if (FL_TEST(re1, KCODE_FIXED) != FL_TEST(re2, KCODE_FIXED)) return Qfalse;
    if (RREGEXP_PTR(re1)->options != RREGEXP_PTR(re2)->options) return Qfalse;
    if (RREGEXP_SRC_LEN(re1) != RREGEXP_SRC_LEN(re2)) return Qfalse;
    if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse;
    if (memcmp(RREGEXP_SRC_PTR(re1), RREGEXP_SRC_PTR(re2), RREGEXP_SRC_LEN(re1)) == 0) {
        return Qtrue;
    }
    return Qfalse;
}

fixed_encoding? → true or false Show source

如果rxp适用于具有任何ASCII兼容编码的字符串,则返回false。否则返回true。

r = /a/
r.fixed_encoding?                               #=> false
r =~ "\u{6666} a"                               #=> 2
r =~ "\xa1\xa2 a".force_encoding("euc-jp")      #=> 2
r =~ "abc".force_encoding("euc-jp")             #=> 0

r = /a/u
r.fixed_encoding?                               #=> true
r.encoding                                      #=> #<Encoding:UTF-8>
r =~ "\u{6666} a"                               #=> 2
r =~ "\xa1\xa2".force_encoding("euc-jp")        #=> ArgumentError
r =~ "abc".force_encoding("euc-jp")             #=> 0

r = /\u{6666}/
r.fixed_encoding?                               #=> true
r.encoding                                      #=> #<Encoding:UTF-8>
r =~ "\u{6666} a"                               #=> 0
r =~ "\xa1\xa2".force_encoding("euc-jp")        #=> ArgumentError
r =~ "abc".force_encoding("euc-jp")             #=> nil
static VALUE
rb_reg_fixed_encoding_p(VALUE re)
{
    if (FL_TEST(re, KCODE_FIXED))
        return Qtrue;
    else
        return Qfalse;
}

hash → integer Show source

根据此正则表达式的文本和选项生成散列。

See also Object#hash.

static VALUE
rb_reg_hash(VALUE re)
{
    st_index_t hashval = reg_hash(re);
    return ST2FIX(hashval);
}

inspect → string Show source

生成一个很好格式化的字符串版本的rxp。也许令人惊讶的是,#inspect实际上会产生比字符串更自然的版本#to_s

/ab+c/ix.inspect        #=> "/ab+c/ix"
static VALUE
rb_reg_inspect(VALUE re)
{
    if (!RREGEXP_PTR(re) || !RREGEXP_SRC(re) || !RREGEXP_SRC_PTR(re)) {
        return rb_any_to_s(re);
    }
    return rb_reg_desc(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), re);
}

match(str) → matchdata or nil Show source

match(str,pos) → matchdata or nil

返回MatchData描述匹配的对象,或者nil不匹配。这相当于在$~正常匹配之后检索特殊变量的值。如果第二个参数存在,它指定字符串中开始搜索的位置。

/(.)(.)(.)/.match("abc")[2]   #=> "b"
/(.)(.)/.match("abc", 1)[2]   #=> "c"

如果给出了块,如果匹配成功,则用MatchData调用块,以便写入

/M(.*)/.match("Matz") do |m|
  puts m[0]
  puts m[1]
end

代替

if m = /M(.*)/.match("Matz")
  puts m[0]
  puts m[1]
end

返回值是这种情况下块执行的值。

static VALUE
rb_reg_match_m(int argc, VALUE *argv, VALUE re)
{
    VALUE result, str, initpos;
    long pos;

    if (rb_scan_args(argc, argv, "11", &str, &initpos) == 2) {
        pos = NUM2LONG(initpos);
    }
    else {
        pos = 0;
    }

    pos = reg_match_pos(re, &str, pos);
    if (pos < 0) {
        rb_backref_set(Qnil);
        return Qnil;
    }
    result = rb_backref_get();
    rb_match_busy(result);
    if (!NIL_P(result) && rb_block_given_p()) {
        return rb_yield(result);
    }
    return result;
}

match?(str) → true or false Show source

match?(str,pos) → true or false

返回a true或者false表示是否匹配正则表达式而不更新$〜和其他相关变量。如果第二个参数存在,它指定字符串中开始搜索的位置。

/R.../.match?("Ruby")    #=> true
/R.../.match?("Ruby", 1) #=> false
/P.../.match?("Ruby")    #=> false
$&                       #=> nil
static VALUE
rb_reg_match_m_p(int argc, VALUE *argv, VALUE re)
{
    long pos = rb_check_arity(argc, 1, 2) > 1 ? NUM2LONG(argv[1]) : 0;
    return rb_reg_match_p(re, argv[0], pos);
}

named_captures → hash Show source

返回表示关于rxp的命名捕获的信息的散列。

散列的一个关键是指定捕获的名称。哈希值是一个数组,它是相应命名捕获的索引列表。

/(?<foo>.)(?<bar>.)/.named_captures
#=> {"foo"=>[1], "bar"=>[2]}

/(?<foo>.)(?<foo>.)/.named_captures
#=> {"foo"=>[1, 2]}

如果没有命名捕获,则返回一个空的散列。

/(.)(.)/.named_captures
#=> {}
static VALUE
rb_reg_named_captures(VALUE re)
{
    VALUE hash = rb_hash_new();
    rb_reg_check(re);
    onig_foreach_name(RREGEXP_PTR(re), reg_named_captures_iter, (void*)hash);
    return hash;
}

names → name1, name2, ...()

以字符串数组的形式返回捕获的名称列表。

/(?<foo>.)(?<bar>.)(?<baz>.)/.names
#=> ["foo", "bar", "baz"]

/(?<foo>.)(?<foo>.)/.names
#=> ["foo"]

/(.)(.)/.names
#=> []
static VALUE
rb_reg_names(VALUE re)
{
    VALUE ary;
    rb_reg_check(re);
    ary = rb_ary_new_capa(onig_number_of_names(RREGEXP_PTR(re)));
    onig_foreach_name(RREGEXP_PTR(re), reg_names_iter, (void*)ary);
    return ary;
}

options → integer Show source

返回与创建此Regexp::new正则表达式时使用的选项对应的位集合(请参阅以了解详细信息。请注意,可在返回的选项中设置其他位:这些位在正则表达式代码内部使用。如果选项为传递给Regexp::new

Regexp::IGNORECASE                  #=> 1
Regexp::EXTENDED                    #=> 2
Regexp::MULTILINE                   #=> 4

/cat/.options                       #=> 0
/cat/ix.options                     #=> 3
Regexp.new('cat', true).options     #=> 1
/\xa1\xa2/e.options                 #=> 16

r = /cat/ix
Regexp.new(r.source, r.options)     #=> /cat/ix
static VALUE
rb_reg_options_m(VALUE re)
{
    int options = rb_reg_options(re);
    return INT2NUM(options);
}

source → str Show source

返回模式的原始字符串。

/ab+c/ix.source #=> "ab+c"

请注意,转义序列保留原样。

/\x20\+/.source  #=> "\\x20\\+"
static VALUE
rb_reg_source(VALUE re)
{
    VALUE str;

    rb_reg_check(re);
    str = rb_str_dup(RREGEXP_SRC(re));
    if (OBJ_TAINTED(re)) OBJ_TAINT(str);
    return str;
}

to_json(*) Show source

将类名(Regexp)与选项o和源s(Regexp或String)一起存储为JSON字符串

# File ext/json/lib/json/add/regexp.rb, line 27
def to_json(*)
  as_json.to_json
end

to_s → str Show source

返回一个包含正则表达式及其选项的字符串(使用(?opts:source)符号),该字符串可以被返回Regexp::new到正则表达式,其语义与原始语言相同(但是,Regexp#==在比较两者时,可能不会返回true,作为源的正则表达式本身可能会有所不同,如示例所示)Regexp#inspect生成一个通常更易读的rxp版本。

r1 = /ab+c/ix           #=> /ab+c/ix
s1 = r1.to_s            #=> "(?ix-m:ab+c)"
r2 = Regexp.new(s1)     #=> /(?ix-m:ab+c)/
r1 == r2                #=> false
r1.source               #=> "ab+c"
r2.source               #=> "(?ix-m:ab+c)"
static VALUE
rb_reg_to_s(VALUE re)
{
    int options, opt;
    const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND;
    long len;
    const UChar* ptr;
    VALUE str = rb_str_buf_new2("(?");
    char optbuf[5];
    rb_encoding *enc = rb_enc_get(re);

    rb_reg_check(re);

    rb_enc_copy(str, re);
    options = RREGEXP_PTR(re)->options;
    ptr = (UChar*)RREGEXP_SRC_PTR(re);
    len = RREGEXP_SRC_LEN(re);
  again:
    if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') {
        int err = 1;
        ptr += 2;
        if ((len -= 2) > 0) {
            do {
                opt = char_to_option((int )*ptr);
                if (opt != 0) {
                    options |= opt;
                }
                else {
                    break;
                }
                ++ptr;
            } while (--len > 0);
        }
        if (len > 1 && *ptr == '-') {
            ++ptr;
            --len;
            do {
                opt = char_to_option((int )*ptr);
                if (opt != 0) {
                    options &= ~opt;
                }
                else {
                    break;
                }
                ++ptr;
            } while (--len > 0);
        }
        if (*ptr == ')') {
            --len;
            ++ptr;
            goto again;
        }
        if (*ptr == ':' && ptr[len-1] == ')') {
            Regexp *rp;
            VALUE verbose = ruby_verbose;
            ruby_verbose = Qfalse;

            ++ptr;
            len -= 2;
            err = onig_new(&rp, ptr, ptr + len, ONIG_OPTION_DEFAULT,
                           enc, OnigDefaultSyntax, NULL);
            onig_free(rp);
            ruby_verbose = verbose;
        }
        if (err) {
            options = RREGEXP_PTR(re)->options;
            ptr = (UChar*)RREGEXP_SRC_PTR(re);
            len = RREGEXP_SRC_LEN(re);
        }
    }

    if (*option_to_str(optbuf, options)) rb_str_buf_cat2(str, optbuf);

    if ((options & embeddable) != embeddable) {
        optbuf[0] = '-';
        option_to_str(optbuf + 1, ~options);
        rb_str_buf_cat2(str, optbuf);
    }

    rb_str_buf_cat2(str, ":");
    if (rb_enc_asciicompat(enc)) {
        rb_reg_expr_str(str, (char*)ptr, len, enc, NULL);
        rb_str_buf_cat2(str, ")");
    }
    else {
        const char *s, *e;
        char *paren;
        ptrdiff_t n;
        rb_str_buf_cat2(str, ")");
        rb_enc_associate(str, rb_usascii_encoding());
        str = rb_str_encode(str, rb_enc_from_encoding(enc), 0, Qnil);

        /* backup encoded ")" to paren */
        s = RSTRING_PTR(str);
        e = RSTRING_END(str);
        s = rb_enc_left_char_head(s, e-1, e, enc);
        n = e - s;
        paren = ALLOCA_N(char, n);
        memcpy(paren, s, n);
        rb_str_resize(str, RSTRING_LEN(str) - n);

        rb_reg_expr_str(str, (char*)ptr, len, enc, NULL);
        rb_str_buf_cat(str, paren, n);
    }
    rb_enc_copy(str, re);

    OBJ_INFECT(str, re);
    return str;
}

~ rxp → integer or nil Show source

匹配rxp与内容匹配$_。相当于。rxp =~ $_

$_ = "input data"
~ /at/   #=> 7
VALUE
rb_reg_match2(VALUE re)
{
    long start;
    VALUE line = rb_lastline_get();

    if (!RB_TYPE_P(line, T_STRING)) {
        rb_backref_set(Qnil);
        return Qnil;
    }

    start = rb_reg_search(re, line, 0, 0);
    if (start < 0) {
        return Qnil;
    }
    start = rb_str_sublen(line, start);
    return LONG2FIX(start);
}
Regexp
Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct