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常规类别之一的字符Letter
,Mark
,Number
,Connector_Punctuation
/[[:ascii:]]/
- ASCII字符集中的字符
U+06F2 is "EXTENDED ARABIC-INDIC DIGIT TWO" /[:digit:]/.match("\u06F2") #=> #<MatchData "\u{06F2}"> /[:upper:][:lower:]/.match("Hello") #=> #<MatchData "He"> /[:xdigit:][:xdigit:]/.match("A6") #=> #<MatchData "A6">
Repetition
到目前为止描述的结构符合单个字符。它们可以跟随一个重复元字符来指定它们需要发生的次数。这种元字符称为量词
。
*
- 零次或多次
+
- 一次或多次
?
- 零次或一次(可选)
{
n
}
- 恰好n
次
{
n
,}
-n
次或更多次
{,
m
}
-m
或更少
{
n
,
m
}
- 至少n
次,最多m
次
- 匹配字符串的开头,即在第一个字符之前。
2. 进入名为的已命名捕获组 paren
3. 匹配一个文字(
,字符串中的第一个字符
4. paren
再次调用该组,即递归回到第二步
5. 重新进入该paren
组
6. 匹配一个文字(
,字符串中的第二个字符
7. 尝试paren
第三次调用,但失败,因为这样做会阻止整体成功的匹配
8. 匹配文字)
,字符串中的第三个字符。标记第二次递归调用的结束
9. 匹配文字)
,即字符串中的第四个字符
10. 匹配string
/\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常规类别之一的成员Letter
,Mark
,Number
,Connector_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_CHIKI
,Old_Italic
,Old_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#match
和String#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
-#{}
只进行一次插值
i
,m
和x
也可以在与所述子表达式级别应用(?
上
-
掉
)
构建体,其使得选项上
,并禁用选项关闭
用于由括号包围的表达。
/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
$~
相当于:: 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
}