類別 Regexp
一個 正規表示式(也稱為 regexp)是一個 比對模式(也稱為 模式)。
正規表示式的一般表示法使用斜線字元包住
/foo/
正規表示式可以套用在一個 目標字串;字串中(如果有)與模式比對的部分稱為 比對,並且可以說 比對到
re = /red/ re.match?('redirect') # => true # Match at beginning of target. re.match?('bored') # => true # Match at end of target. re.match?('credit') # => true # Match within target. re.match?('foo') # => false # No match.
Regexp 用法¶ ↑
正規表示式可以用於
-
根據給定的模式擷取子字串
re = /foo/ # => /foo/ re.match('food') # => #<MatchData "foo"> re.match('good') # => nil
-
判斷字串是否符合給定的模式
re.match?('food') # => true re.match?('good') # => false
請參閱區段 方法 match?。
-
作為其他類別和模組中某些方法呼叫的引數;大多數此類方法接受的引數可以是字串或(功能強大的)正規表示法。
請參閱 正規表示法方法。
正規表示法物件¶ ↑
正規表示法物件具有
建立正規表示法¶ ↑
可以使用下列方式建立正規表示法
-
使用斜線字元的正規表示法文字 (請參閱 正規表示法文字)
# This is a very common usage. /foo/ # => /foo/
-
%r
正規表示法文字 (請參閱 %r:正規表示法文字)# Same delimiter character at beginning and end; # useful for avoiding escaping characters %r/name\/value pair/ # => /name\/value pair/ %r:name/value pair: # => /name\/value pair/ %r|name/value pair| # => /name\/value pair/ # Certain "paired" characters can be delimiters. %r[foo] # => /foo/ %r{foo} # => /foo/ %r(foo) # => /foo/ %r<foo> # => /foo/
-
方法
Regexp.new
。
方法 match
¶ ↑
每個方法 Regexp#match
、String#match
和 Symbol#match
如果找到符合項,則會傳回 MatchData
物件,否則傳回 nil
;每個方法也會設定 全域變數
'food'.match(/foo/) # => #<MatchData "foo"> 'food'.match(/bar/) # => nil
運算子 =~
¶ ↑
每個運算子 Regexp#=~
、String#=~
和 Symbol#=~
如果找到符合項,則會傳回整數偏移量,否則傳回 nil
;每個方法也會設定 全域變數
/bar/ =~ 'foo bar' # => 4 'foo bar' =~ /bar/ # => 4 /baz/ =~ 'foo bar' # => nil
方法 match?
¶ ↑
每個方法 Regexp#match?
、String#match?
和 Symbol#match?
如果找到符合項,則會傳回 true
,否則傳回 false
;沒有任何方法會設定 全域變數
'food'.match?(/foo/) # => true 'food'.match?(/bar/) # => false
全域變數¶ ↑
某些以正規表示法為導向的方法會將值指定給全域變數
受影響的全局變數為
-
$~
:傳回MatchData
物件或nil
。 -
$&
:傳回字串中相符的部分或nil
。 -
$`
:傳回相符部分左側的字串部分或nil
。 -
$'
:傳回相符部分右側的字串部分或nil
。 -
$+
:傳回最後相符的群組或nil
。 -
$1
、$2
等:傳回第一、第二等相符的群組或nil
。請注意,$0
非常不同;它會傳回目前執行程式名稱。
範例
# Matched string, but no matched groups. 'foo bar bar baz'.match('bar') $~ # => #<MatchData "bar"> $& # => "bar" $` # => "foo " $' # => " bar baz" $+ # => nil $1 # => nil # Matched groups. /s(\w{2}).*(c)/.match('haystack') $~ # => #<MatchData "stac" 1:"ta" 2:"c"> $& # => "stac" $` # => "hay" $' # => "k" $+ # => "c" $1 # => "ta" $2 # => "c" $3 # => nil # No match. 'foo'.match('bar') $~ # => nil $& # => nil $` # => nil $' # => nil $+ # => nil $1 # => nil
請注意,Regexp#match?
、String#match?
和 Symbol#match?
不會設定全局變數。
來源¶ ↑
如上所示,最簡單的正規表示法使用文字表達式作為其來源
re = /foo/ # => /foo/ re.match('food') # => #<MatchData "foo"> re.match('good') # => nil
豐富的可用子表達式集合賦予正規表示法強大的功能和彈性
特殊字元¶ ↑
正規表示法特殊字元,稱為元字元,在特定脈絡中具有特殊意義;根據脈絡,這些有時是元字元
. ? - + * ^ \ | $ ( ) [ ] { }
若要以文字方式相符元字元,請使用反斜線跳脫
# Matches one or more 'o' characters. /o+/.match('foo') # => #<MatchData "oo"> # Would match 'o+'. /o\+/.match('foo') # => nil
若要以文字方式相符反斜線,請使用反斜線跳脫
/\./.match('\.') # => #<MatchData "."> /\\./.match('\.') # => #<MatchData "\\.">
方法
Regexp.escape
傳回跳脫字串
Regexp.escape('.?-+*^\|$()[]{}') # => "\\.\\?\\-\\+\\*\\^\\\\\\|\\$\\(\\)\\[\\]\\{\\}"
來源文字¶ ↑
來源文字在很大程度上表現得像雙引號字串;請參閱 字串文字。
特別是,來源文字可能包含內插表達式
s = 'foo' # => "foo" /#{s}/ # => /foo/ /#{s.capitalize}/ # => /Foo/ /#{2 + 2}/ # => /4/
一般字串文字和來源文字之間有差異;請參閱 簡寫字元類別。
-
一般字串文字中的
\s
等於空白字元;在來源文字中,它是相符空白字元的簡寫。 -
在一般字串文字中,這些是(不必要)跳脫的字元;在來源文字中,它們是各種相符字元的簡寫
\w \W \d \D \h \H \S \R
字元類別¶ ↑
字元類別以方括弧分隔;它指定某些字元在目標字串的特定點相符
# This character class will match any vowel. re = /B[aeiou]rd/ re.match('Bird') # => #<MatchData "Bird"> re.match('Bard') # => #<MatchData "Bard"> re.match('Byrd') # => nil
字元類別可以包含連字元號來指定字元範圍
# These regexps have the same effect. /[abcdef]/.match('foo') # => #<MatchData "f"> /[a-f]/.match('foo') # => #<MatchData "f"> /[a-cd-f]/.match('foo') # => #<MatchData "f">
當字元類別的第一個字元是插入符號 (^
) 時,類別的意義會反轉:它會比對任何字元,除了指定字元之外。
/[^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]/
簡寫字元類別¶ ↑
下列每個元字元都作為字元類別的簡寫
-
/./
:比對任何字元,除了換行符號/./.match('foo') # => #<MatchData "f"> /./.match("\n") # => nil
-
/./m
:比對任何字元,包括換行符號;請參閱 多行模式/./m.match("\n") # => #<MatchData "\n">
-
/\w/
:比對字元字元:等於[a-zA-Z0-9_]
/\w/.match(' foo') # => #<MatchData "f"> /\w/.match(' _') # => #<MatchData "_"> /\w/.match(' ') # => nil
-
/\W/
:比對非字元字元:等於[^a-zA-Z0-9_]
/\W/.match(' ') # => #<MatchData " "> /\W/.match('_') # => nil
-
/\d/
:比對數字字元:等於[0-9]
/\d/.match('THX1138') # => #<MatchData "1"> /\d/.match('foo') # => nil
-
/\D/
:比對非數字字元:等於[^0-9]
/\D/.match('123Jump!') # => #<MatchData "J"> /\D/.match('123') # => nil
-
/\h/
:比對十六進位數字字元:等於[0-9a-fA-F]
/\h/.match('xyz fedcba9876543210') # => #<MatchData "f"> /\h/.match('xyz') # => nil
-
/\H/
:比對非十六進位數字字元:等於[^0-9a-fA-F]
/\H/.match('fedcba9876543210xyz') # => #<MatchData "x"> /\H/.match('fedcba9876543210') # => nil
-
/\s/
:比對空白字元:等於/[ \t\r\n\f\v]/
/\s/.match('foo bar') # => #<MatchData " "> /\s/.match('foo') # => nil
-
/\S/
:比對非空白字元:等於/[^ \t\r\n\f\v]/
/\S/.match(" \t\r\n\f\v foo") # => #<MatchData "f"> /\S/.match(" \t\r\n\f\v") # => nil
-
/\R/
:比對換行符號,與平台無關/\R/.match("\r") # => #<MatchData "\r"> # Carriage return (CR) /\R/.match("\n") # => #<MatchData "\n"> # Newline (LF) /\R/.match("\f") # => #<MatchData "\f"> # Formfeed (FF) /\R/.match("\v") # => #<MatchData "\v"> # Vertical tab (VT) /\R/.match("\r\n") # => #<MatchData "\r\n"> # CRLF /\R/.match("\u0085") # => #<MatchData "\u0085"> # Next line (NEL) /\R/.match("\u2028") # => #<MatchData "\u2028"> # Line separator (LSEP) /\R/.match("\u2029") # => #<MatchData "\u2029"> # Paragraph separator (PSEP)
錨點¶ ↑
錨點是元序列,它比對目標字串中字元之間的零寬度位置。
對於沒有錨點的子表達式,比對可以從目標字串中的任何位置開始
/real/.match('surrealist') # => #<MatchData "real">
對於有錨點的子表達式,比對必須從比對的錨點開始。
邊界錨點¶ ↑
這些錨點每個都比對一個邊界
-
^
:比對行首/^bar/.match("foo\nbar") # => #<MatchData "bar"> /^ar/.match("foo\nbar") # => nil
-
$
:比對行尾/bar$/.match("foo\nbar") # => #<MatchData "bar"> /ba$/.match("foo\nbar") # => nil
-
\A
:比對字串開頭/\Afoo/.match('foo bar') # => #<MatchData "foo"> /\Afoo/.match(' foo bar') # => nil
-
\Z
:比對字串結尾;如果字串以單一換行符號結尾,它會比對在結尾換行符號之前/foo\Z/.match('bar foo') # => #<MatchData "foo"> /foo\Z/.match('foo bar') # => nil /foo\Z/.match("bar foo\n") # => #<MatchData "foo"> /foo\Z/.match("bar foo\n\n") # => nil
-
\z
:比對字串結尾/foo\z/.match('bar foo') # => #<MatchData "foo"> /foo\z/.match('foo bar') # => nil /foo\z/.match("bar foo\n") # => nil
-
\b
:不在括號內時比對字元邊界;在括號內時比對退格鍵 ("0x08"
)/foo\b/.match('foo bar') # => #<MatchData "foo"> /foo\b/.match('foobar') # => nil
-
\B
:比對非字詞邊界/foo\B/.match('foobar') # => #<MatchData "foo"> /foo\B/.match('foo bar') # => nil
-
\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
環顧錨點¶ ↑
前瞻錨點
-
(?=pat)
:正前瞻肯定:確保後續字元符合 pat,但不會將這些字元包含在比對的子字串中。 -
(?!pat)
:負前瞻否定:確保後續字元不符合 pat,但不會將這些字元包含在比對的子字串中。
後顧錨點
-
(?<=pat)
:正後顧肯定:確保前一個字元符合 pat,但不會將這些字元包含在比對的子字串中。 -
(?<!pat)
:負後顧否定:確保前一個字元不符合 pat,但不會將這些字元包含在比對的子字串中。
下方的範例使用正前瞻和正後顧來比對出現在 … 標籤中的文字,但不包含比對中的標籤
/(?<=<b>)\w+(?=<\/b>)/.match("Fortune favors the <b>bold</b>.") # => #<MatchData "bold">
比對重設錨點¶ ↑
-
\K
:比對重設:正則表示法中\K
前面的比對內容會從結果中排除。例如,以下兩個正則表示法幾乎等效/ab\Kc/.match('abc') # => #<MatchData "c"> /(?<=ab)c/.match('abc') # => #<MatchData "c">
它們比對相同的字串,且
$&
等於'c'
,而比對位置不同。以下兩個正則表示法也是如此
/(a)\K(b)\Kc/ /(?<=(?<=(a))(b))c/
交替¶ ↑
垂直線元字元 (|
) 可用於括弧內表示交替:兩個或多個子表示式,其中任何一個都可能比對目標字串。
兩個交替
re = /(a|b)/ re.match('foo') # => nil re.match('bar') # => #<MatchData "b" 1:"b">
四個交替
re = /(a|b|c|d)/ re.match('shazam') # => #<MatchData "a" 1:"a"> re.match('cold') # => #<MatchData "c" 1:"c">
每個交替都是一個子表示式,且可能由其他子表示式組成
re = /([a-c]|[x-z])/ re.match('bar') # => #<MatchData "b" 1:"b"> re.match('ooz') # => #<MatchData "z" 1:"z">
方法 Regexp.union
提供一個方便的方法來建構具有交替的正則表示法。
量詞¶ ↑
一個簡單的正則表示法比對一個字元
/\w/.match('Hello') # => #<MatchData "H">
新增的量詞指定需要或允許多少比對
-
*
- 比對零次或多次/\w*/.match('') # => #<MatchData ""> /\w*/.match('x') # => #<MatchData "x"> /\w*/.match('xyz') # => #<MatchData "yz">
-
+
- 比對一次或多次/\w+/.match('') # => nil /\w+/.match('x') # => #<MatchData "x"> /\w+/.match('xyz') # => #<MatchData "xyz">
-
?
- 匹配零次或一次/\w?/.match('') # => #<MatchData ""> /\w?/.match('x') # => #<MatchData "x"> /\w?/.match('xyz') # => #<MatchData "x">
-
{
n}
- 精確匹配 n 次/\w{2}/.match('') # => nil /\w{2}/.match('x') # => nil /\w{2}/.match('xyz') # => #<MatchData "xy">
-
{
min,}
- 匹配 min 次或更多次/\w{2,}/.match('') # => nil /\w{2,}/.match('x') # => nil /\w{2,}/.match('xy') # => #<MatchData "xy"> /\w{2,}/.match('xyz') # => #<MatchData "xyz">
-
{,
max}
- 匹配 max 次或更少次/\w{,2}/.match('') # => #<MatchData ""> /\w{,2}/.match('x') # => #<MatchData "x"> /\w{,2}/.match('xyz') # => #<MatchData "xy">
-
{
min,
max}
- 匹配至少 min 次且最多 max 次/\w{1,2}/.match('') # => nil /\w{1,2}/.match('x') # => #<MatchData "x"> /\w{1,2}/.match('xyz') # => #<MatchData "xy">
貪婪、懶惰或獨佔匹配¶ ↑
量詞匹配可能是貪婪、懶惰或獨佔
-
在貪婪匹配中,在仍允許整體匹配成功的情況下,匹配盡可能多的出現次數。貪婪量詞:
*
、+
、?
、{min, max}
及其變體。 -
在懶惰匹配中,匹配最少數量的出現次數。懶惰量詞:
*?
、+?
、??
、{min, max}?
及其變體。 -
在獨佔匹配中,一旦找到匹配項,就不會回溯;保留該匹配項,即使它危及整體匹配。獨佔量詞:
*+
、++
、?+
。請注意,{min, max}
及其變體不支援獨佔匹配。
更多
群組和擷取¶ ↑
一個簡單的正規表示式有(最多)一個匹配項
re = /\d\d\d\d-\d\d-\d\d/ re.match('1943-02-04') # => #<MatchData "1943-02-04"> re.match('1943-02-04').size # => 1 re.match('foo') # => nil
新增一對或多對括號 (子表示式)
,定義群組,這可能會產生多個匹配的子字串,稱為擷取
re = /(\d\d\d\d)-(\d\d)-(\d\d)/ re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04"> re.match('1943-02-04').size # => 4
第一個擷取是整個匹配的字串;其他擷取是來自群組的匹配子字串。
一個群組可能有一個 量詞
re = /July 4(th)?/ re.match('July 4') # => #<MatchData "July 4" 1:nil> re.match('July 4th') # => #<MatchData "July 4th" 1:"th"> re = /(foo)*/ re.match('') # => #<MatchData "" 1:nil> re.match('foo') # => #<MatchData "foo" 1:"foo"> re.match('foofoo') # => #<MatchData "foofoo" 1:"foo"> re = /(foo)+/ re.match('') # => nil re.match('foo') # => #<MatchData "foo" 1:"foo"> re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
回傳的 MatchData 物件提供對匹配子字串的存取
re = /(\d\d\d\d)-(\d\d)-(\d\d)/ md = re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04"> md[0] # => "1943-02-04" md[1] # => "1943" md[2] # => "02" md[3] # => "04"
非擷取群組¶ ↑
群組可以設為非擷取;它仍然是一個群組(例如,可以有一個量詞),但其配對的子字串不會包含在擷取中。
非擷取群組以 ?:
開頭(在括號內)
# Don't capture the year. re = /(?:\d\d\d\d)-(\d\d)-(\d\d)/ md = re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"02" 2:"04">
反向參照¶ ↑
群組配對也可以在正規表示法本身中參照;這樣的參照稱為反向參照
/[csh](..) [csh]\1 in/.match('The cat sat in the hat') # => #<MatchData "cat sat in" 1:"at">
此表格顯示正規表示法中每個子表示式如何配對目標字串中的子字串
| Subexpression in Regexp | Matching Substring in Target String | |---------------------------|-------------------------------------| | First '[csh]' | Character 'c' | | '(..)' | First substring 'at' | | First space ' ' | First space character ' ' | | Second '[csh]' | Character 's' | | '\1' (backreference 'at') | Second substring 'at' | | ' in' | Substring ' in' |
正規表示法可以包含任意數量的群組
-
對於大量的群組
-
一般的
\n
表示法僅適用於範圍 (1..9) 中的 n。 -
MatchData[n]
表示法適用於任何非負的 n。
-
-
\0
是特殊反向參照,用於參照整個配對字串;它不能用於正規表示法本身中,但可以在正規表示法外部使用(例如,在替換方法呼叫中)'The cat sat in the hat'.gsub(/[csh]at/, '\0s') # => "The cats sats in the hats"
命名擷取¶ ↑
如上所述,可以透過其數字參照擷取。擷取也可以有一個名稱,其前綴為 ?<name>
或 ?'name'
,名稱(符號)可以用作 MatchData[]
中的索引
md = /\$(?<dollars>\d+)\.(?'cents'\d+)/.match("$3.67") # => #<MatchData "$3.67" dollars:"3" cents:"67"> md[:dollars] # => "3" md[:cents] # => "67" # The capture numbers are still valid. md[2] # => "67"
當正規表示法包含命名擷取時,沒有未命名擷取
/\$(?<dollars>\d+)\.(\d+)/.match("$3.67") # => #<MatchData "$3.67" dollars:"3">
命名群組可以反向參照為 \k<name>
/(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy') # => #<MatchData "ototo" vowel:"o">
當(且僅當)正規表示法包含命名擷取群組並出現在 =~
算子之前時,擷取的子字串會指派給具有對應名稱的局部變數
/\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ '$3.67' dollars # => "3" cents # => "67"
方法 Regexp#named_captures
傳回擷取名稱和子字串的雜湊;方法 Regexp#names
傳回擷取名稱的陣列。
原子群組¶ ↑
群組可以使用 (?>
子表示式)
設為原子。
這會導致子表示式獨立於表示式的其餘部分進行配對,以便配對的子字串在配對的其餘部分中固定,除非必須放棄整個子表示式並隨後重新檢視。
這樣,子表示式被視為不可分割的整體。原子群組通常用於最佳化模式,以防止不必要的回溯。
範例(沒有原子群組)
/".*"/.match('"Quote"') # => #<MatchData "\"Quote\"">
分析
-
模式中開頭的子表達式
"
與目標字串中的第一個字元"
相符。 -
下一個子表達式
.*
與下一個子字串Quote“
相符(包含尾隨的雙引號)。 -
現在目標字串中沒有任何內容與模式中尾隨的子表達式
"
相符;這會導致整體比對失敗。 -
比對的子字串回溯一個位置:
Quote
。 -
最後一個子表達式
"
現在與最後一個子字串"
相符,整體比對成功。
如果子表達式 .*
是原子性分組,回溯會被停用,整體比對會失敗
/"(?>.*)"/.match('"Quote"') # => nil
原子性分組會影響效能;請參閱 原子性分組。
子表達式呼叫¶ ↑
如上所示,回溯參考號碼 (\n
) 或名稱 (\k<name>
) 可存取擷取的子字串;也可以透過號碼 (\gn
) 或名稱 (\g<name>
) 存取對應的 regexp 子表達式
/\A(?<paren>\(\g<paren>*\))*\z/.match('(())') # ^1 # ^2 # ^3 # ^4 # ^5 # ^6 # ^7 # ^8 # ^9 # ^10
模式
-
與字串開頭相符,也就是第一個字元之前。
-
進入命名分組
paren
。 -
與字串中的第一個字元
'('
相符。 -
再次呼叫
paren
分組,也就是遞迴回到第二個步驟。 -
再次進入
paren
分組。 -
與字串中的第二個字元
'('
相符。 -
嘗試第三次呼叫
paren
,但失敗,因為這樣做會阻止整體比對成功。 -
與字串中的第三個字元
')'
相符;標示第二次遞迴呼叫的結束 -
與字串中的第四個字元
')'
相符。 -
與字串的結尾相符。
請參閱 子表達式呼叫。
條件式¶ ↑
條件式結構採用 (?(cond)yes|no)
形式,其中
-
cond 可以是擷取號碼或名稱。
-
如果 cond 有被擷取,要套用的比對是 yes;否則要套用的比對是 no。
-
如果不需要,可以省略
|no
。
範例
re = /\A(foo)?(?(1)(T)|(F))\z/ re.match('fooT') # => #<MatchData "fooT" 1:"foo" 2:"T" 3:nil> re.match('F') # => #<MatchData "F" 1:nil 2:nil 3:"F"> re.match('fooF') # => nil re.match('T') # => nil re = /\A(?<xyzzy>foo)?(?(<xyzzy>)(T)|(F))\z/ re.match('fooT') # => #<MatchData "fooT" xyzzy:"foo"> re.match('F') # => #<MatchData "F" xyzzy:nil> re.match('fooF') # => nil re.match('T') # => nil
不存在運算子¶ ↑
不存在運算子是一個特殊分組,與不與包含的子表達式相符的任何內容相符。
/(?~real)/.match('surrealist') # => #<MatchData "surrea"> /(?~real)ist/.match('surrealist') # => #<MatchData "ealist"> /sur(?~real)ist/.match('surrealist') # => nil
Unicode¶ ↑
Unicode 屬性¶ ↑
/\p{property_name}/
結構(小寫 p
)使用 Unicode 屬性名稱與字元相符,很像字元類別;屬性 Alpha
指定字母字元
/\p{Alpha}/.match('a') # => #<MatchData "a"> /\p{Alpha}/.match('1') # => nil
屬性可以在名稱前加上插入符號 (^
) 來反轉
/\p{^Alpha}/.match('1') # => #<MatchData "1"> /\p{^Alpha}/.match('a') # => nil
或使用 \P
(大寫 P
)
/\P{Alpha}/.match('1') # => #<MatchData "1"> /\P{Alpha}/.match('a') # => nil
請參閱 Unicode 屬性,以取得基於許多屬性的正規表示法。
一些常用的屬性對應於 POSIX 方括號表示法
-
/\p{Alnum}/
:字母數字字元 -
/\p{Alpha}/
:字母字元 -
/\p{Blank}/
:空白或標籤 -
/\p{Cntrl}/
:控制字元 -
/\p{Digit}/
:數字字元,類似字元 -
/\p{Lower}/
:小寫字母字元 -
/\p{Print}/
:類似\p{Graph}
,但包含空白字元 -
/\p{Punct}/
:標點符號字元 -
/\p{Space}/
:空白字元 ([:blank:]
、換行、回車等) -
/\p{Upper}/
:大寫字母 -
/\p{XDigit}/
:十六進位數字中允許的數字 (即 0-9a-fA-F)
以下也常使用
-
/\p{Emoji}/
:Unicode 表情符號。 -
/\p{Graph}/
:非空白字元 (不包括空白、控制字元和類似字元)。 -
/\p{Word}/
:這些 Unicode 字元類別之一的成員 (請參閱下方) 或具有這些 Unicode 屬性之一-
Unicode 類別
-
標記
(M
)。 -
十進位數字
(Nd
) -
連接符號標點
(Pc
)。
-
-
Unicode 屬性
-
字母
-
連接控制
-
-
-
/\p{ASCII}/
:ASCII 字元集中的字元。 -
/\p{Any}/
:任何 Unicode 字元 (包括未指派的字元)。 -
/\p{Assigned}/
:已指派的字元。
Unicode 字元類別¶ ↑
Unicode 字元類別名稱
-
可能是其全名或縮寫。
-
不區分大小寫。
-
將空白、連字元和底線視為等同。
範例
/\p{lu}/ # => /\p{lu}/ /\p{LU}/ # => /\p{LU}/ /\p{Uppercase Letter}/ # => /\p{Uppercase Letter}/ /\p{Uppercase_Letter}/ # => /\p{Uppercase_Letter}/ /\p{UPPERCASE-LETTER}/ # => /\p{UPPERCASE-LETTER}/
以下是 Unicode 字元類別縮寫和名稱。每個類別中字元的列舉位於連結中。
字母
-
L
、Letter
:LC
、Lm
或Lo
。 -
LC
、Cased_Letter
:Ll
、Lt
或Lu
。
符號
數字
標點符號
-
P
,標點符號
:Pc
、Pd
、Pe
、Pf
、Pi
、Po
或Ps
。 -
S
,符號
:Sc
、Sk
、Sm
或So
。 -
Z
,分隔符號
:Zl
、Zp
或Zs
。 -
C
,其他
:Cc
、Cf
、Cn
、Co
或Cs
。
Unicode 碼表和區塊¶ ↑
Unicode 屬性包括
-
Unicode 碼表;請參閱 支援的碼表。
-
Unicode 區塊;請參閱 支援的區塊。
POSIX 方括號表示法¶ ↑
POSIX 方括號表示法 也類似於字元類別。這些表示法提供上述內容的可攜式替代方案,並具有涵蓋非 ASCII 字元的額外好處
-
/\d/
僅匹配 ASCII 十進制數字0
到9
。 -
/[[:digit:]]/
匹配 Unicode十進制數字
(Nd
) 類別中的任何字元;請參閱下方。
POSIX 方括號表示法
-
/[[:digit:]]/
:匹配 Unicode 數字/[[:digit:]]/.match('9') # => #<MatchData "9"> /[[:digit:]]/.match("\u1fbf9") # => #<MatchData "9">
-
/[[:xdigit:]]/
:匹配十六進制數字中允許的數字;等於[0-9a-fA-F]
。 -
/[[:upper:]]/
:匹配 Unicode 大寫字母/[[:upper:]]/.match('A') # => #<MatchData "A"> /[[:upper:]]/.match("\u00c6") # => #<MatchData "Æ">
-
/[[:lower:]]/
:匹配 Unicode 小寫字母/[[:lower:]]/.match('a') # => #<MatchData "a"> /[[:lower:]]/.match("\u01fd") # => #<MatchData "ǽ">
-
/[[:alpha:]]/
:匹配/[[:upper:]]/
或/[[:lower:]]/
。 -
/[[:alnum:]]/
:符合/[[:alpha:]]/
或/[[:digit:]]/
。 -
/[[:space:]]/
:符合 Unicode 空白字元/[[:space:]]/.match(' ') # => #<MatchData " "> /[[:space:]]/.match("\u2005") # => #<MatchData " ">
-
/[[:blank:]]/
:符合/[[:space:]]/
或 tab 字元/[[:blank:]]/.match(' ') # => #<MatchData " "> /[[:blank:]]/.match("\u2005") # => #<MatchData " "> /[[:blank:]]/.match("\t") # => #<MatchData "\t">
-
/[[:cntrl:]]/
:符合 Unicode 控制字元/[[:cntrl:]]/.match("\u0000") # => #<MatchData "\u0000"> /[[:cntrl:]]/.match("\u009f") # => #<MatchData "\u009F">
-
/[[:graph:]]/
:符合除了/[[:space:]]/
或/[[:cntrl:]]/
以外的任何字元。 -
/[[:print:]]/
:符合/[[:graph:]]/
或空白字元。 -
/[[:punct:]]/
:符合任何 (Unicode 標點字元}[www.compart.com/en/unicode/category/Po]
Ruby 也支援這些 (非 POSIX) 方括號表示式
-
/[[:ascii:]]/
:符合 ASCII 字元集中的字元。 -
/[[:word:]]/
:符合下列 Unicode 字元類別或具有下列 Unicode 屬性的字元-
Unicode 類別
-
標記
(M
)。 -
十進位數字
(Nd
) -
連接符號標點
(Pc
)。
-
-
Unicode 屬性
-
字母
-
連接控制
-
-
註解¶ ↑
可以使用 (?#
註解)
結構在正規表示式模式中加入註解,其中 註解 是要忽略的子字串。正規表示式引擎忽略的任意文字
/foo(?#Ignore me)bar/.match('foobar') # => #<MatchData "foobar">
註解不能包含未跳脫的終止字元。
另請參閱 延伸模式。
模式¶ ↑
下列每個修飾詞都為正規表示式設定模式
可以套用其中任何一個、全部或一個都沒有。
修飾詞 i
、m
和 x
可以套用在子表示式
-
(?修飾詞)
為後續子表示式開啟模式 -
(?-修飾詞)
為後續子表示式關閉模式 -
(?修飾詞:子表示式)
為群組中的 子表示式 開啟模式 -
(?-修飾詞:子表示式)
為群組中的 子表示式 關閉模式
範例
re = /(?i)te(?-i)st/ re.match('test') # => #<MatchData "test"> re.match('TEst') # => #<MatchData "TEst"> re.match('TEST') # => nil re.match('teST') # => nil re = /t(?i:e)st/ re.match('test') # => #<MatchData "test"> re.match('tEst') # => #<MatchData "tEst"> re.match('tEST') # => nil
方法 Regexp#options
傳回一個整數,其值顯示不分大小寫模式、多行模式和延伸模式的設定。
不分大小寫模式¶ ↑
預設情況下,regexp 會區分大小寫
/foo/.match('FOO') # => nil
修改器 i
可啟用不區分大小寫模式
/foo/i.match('FOO') # => #<MatchData "FOO">
方法 Regexp#casefold?
會傳回模式是否不區分大小寫。
多行模式¶ ↑
Ruby 中的多行模式通常稱為「點全部模式」
-
沒有
m
修改器時,子表示式.
不會比對換行/a.c/.match("a\nc") # => nil
-
有修改器時,它會比對
/a.c/m.match("a\nc") # => #<MatchData "a\nc">
與其他語言不同,修改器 m
不會影響錨定 ^
和 $
。這些錨定在 Ruby 中總是會比對行界線。
延伸模式¶ ↑
修改器 x
可啟用延伸模式,表示
-
模式中的字元空白會被忽略。
-
字元
#
會將其包含行的剩餘部分標記為註解,在比對時也會被忽略。
在延伸模式中,空白和註解可用於形成自文件化的 regexp。
Regexp
不在延伸模式中(比對一些羅馬數字)
pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$' re = /#{pattern}/ re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
Regexp
在延伸模式中
pattern = <<-EOT ^ # beginning of string M{0,3} # thousands - 0 to 3 Ms (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs), # or 500-800 (D, followed by 0 to 3 Cs) (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs), # or 50-80 (L, followed by 0 to 3 Xs) (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is), # or 5-8 (V, followed by 0 to 3 Is) $ # end of string EOT re = /#{pattern}/x re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
內插模式¶ ↑
修改器 o
表示第一次遇到帶有內插的字面 regexp 時,產生的 Regexp
物件會被儲存,並用於該字面 regexp 的所有未來評估。沒有修改器 o
時,產生的 Regexp
就不會被儲存,因此字面 regexp 的每次評估都會產生新的 Regexp
物件。
沒有修改器 o
def letters; sleep 5; /[A-Z][a-z]/; end words = %w[abc def xyz] start = Time.now words.each {|word| word.match(/\A[#{letters}]+\z/) } Time.now - start # => 15.0174892
有修改器 o
start = Time.now words.each {|word| word.match(/\A[#{letters}]+\z/o) } Time.now - start # => 5.0010866
請注意,如果字面 regexp 沒有內插,則 o
行為是預設值。
編碼¶ ↑
預設情況下,只包含 US-ASCII 字元的 regexp 會有 US-ASCII 編碼
re = /foo/ re.source.encoding # => #<Encoding:US-ASCII> re.encoding # => #<Encoding:US-ASCII>
包含非 US-ASCII 字元的正規表示法會假設使用來源編碼。可以用下列修改器之一覆寫此設定。
-
/pat/n
:如果只包含 US-ASCII 字元,則為 US-ASCII,否則為 ASCII-8BIT/foo/n.encoding # => #<Encoding:US-ASCII> /foo\xff/n.encoding # => #<Encoding:ASCII-8BIT> /foo\x7f/n.encoding # => #<Encoding:US-ASCII>
-
/pat/u
:UTF-8/foo/u.encoding # => #<Encoding:UTF-8>
-
/pat/e
:EUC-JP/foo/e.encoding # => #<Encoding:EUC-JP>
-
/pat/s
:Windows-31J/foo/s.encoding # => #<Encoding:Windows-31J>
regexp 可以與目標字串比對,當
-
它們有相同的編碼。
-
regexp 的編碼是固定編碼,而且字串只包含 ASCII 字元。
Method
Regexp#fixed_encoding?
會傳回 regexp 是否有固定編碼。
如果嘗試比對不相容的編碼,則會引發 Encoding::CompatibilityError
例外。
範例
re = eval("# encoding: ISO-8859-1\n/foo\\xff?/") re.encoding # => #<Encoding:ISO-8859-1> re =~ "foo".encode("UTF-8") # => 0 re =~ "foo\u0100" # Raises Encoding::CompatibilityError
編碼可以透過在 Regexp.new
的第二個引數中包含 Regexp::FIXEDENCODING
來明確固定
# Regexp with encoding ISO-8859-1. re = Regexp.new("a".force_encoding('iso-8859-1'), Regexp::FIXEDENCODING) re.encoding # => #<Encoding:ISO-8859-1> # Target string with encoding UTF-8. s = "a\u3042" s.encoding # => #<Encoding:UTF-8> re.match(s) # Raises Encoding::CompatibilityError.
逾時¶ ↑
當正規表示式來源或目標字串來自不可信的輸入時,惡意的值可能會成為拒絕服務攻擊;為防止此類攻擊,最好設定逾時。
正規表示式有兩個逾時值
-
類別預設逾時,用於實例逾時為
nil
的正規表示式;此預設值最初為nil
,且可透過方法Regexp.timeout=
設定Regexp.timeout # => nil Regexp.timeout = 3.0 Regexp.timeout # => 3.0
-
實例逾時,預設為
nil
,且可在Regexp.new
中設定re = Regexp.new('foo', timeout: 5.0) re.timeout # => 5.0
當 regexp.timeout 為 nil
時,逾時會「傳遞」至 Regexp.timeout
;當 regexp.timeout 為非 nil
時,該值會控制逾時
| regexp.timeout Value | Regexp.timeout Value | Result | |----------------------|----------------------|-----------------------------| | nil | nil | Never times out. | | nil | Float | Times out in Float seconds. | | Float | Any | Times out in Float seconds. |
最佳化¶ ↑
對於模式和目標字串的某些值,比對時間可能會以多項式或指數方式隨著輸入大小而增加;由此產生的潛在漏洞是 正規表示式拒絕服務 (ReDoS) 攻擊。
正規表示式比對可以套用最佳化來防止 ReDoS 攻擊。套用最佳化後,比對時間會以線性方式(而非多項式或指數方式)隨著輸入大小而增加,且無法進行 ReDoS 攻擊。
如果模式符合下列條件,則會套用此最佳化
-
沒有反向參照。
-
沒有子表示式呼叫。
-
沒有巢狀環顧錨點或原子群組。
-
沒有帶計數的巢狀量詞(即沒有巢狀
{n}
、{min,}
、{,max}
或{min,max}
樣式的量詞)
您可以使用 Regexp.linear_time?
方法來判斷模式是否符合這些條件
Regexp.linear_time?(/a*/) # => true Regexp.linear_time?('a*') # => true Regexp.linear_time?(/(a*)\1/) # => false
但是,即使該方法傳回 true
,不可信的來源也可能不安全,因為最佳化會使用記憶化(可能會導致大量記憶體消耗)。
參考資料¶ ↑
閱讀(線上 PDF 書籍)
-
Mastering Regular Expressions,作者為 Jeffrey E.F. Friedl。
-
正則表達式食譜作者為 Jan Goyvaerts 和 Steven Levithan。
探索、測試(互動式線上編輯器)
常數
- EXTENDED
請參閱
Regexp.options
和Regexp.new
- FIXEDENCODING
請參閱
Regexp.options
和Regexp.new
- IGNORECASE
請參閱
Regexp.options
和Regexp.new
- MULTILINE
請參閱
Regexp.options
和Regexp.new
- NOENCODING
請參閱
Regexp.options
和Regexp.new
公開類別方法
別名為 Regexp.new
傳回一個新的字串,其中會跳脫正則表達式中具有特殊意義的任何字元
s = Regexp.escape('\*?{}.') # => "\\\\\\*\\?\\{\\}\\."
對於任何字串 s
,此呼叫會傳回一個 MatchData
物件
r = Regexp.new(Regexp.escape(s)) # => /\\\\\\\*\\\?\\\{\\\}\\\./ r.match(s) # => #<MatchData "\\\\\\*\\?\\{\\}\\.">
static VALUE rb_reg_s_quote(VALUE c, VALUE str) { return rb_reg_quote(reg_operand(str, TRUE)); }
請參閱 as_json
。
# File ext/json/lib/json/add/regexp.rb, line 9 def self.json_create(object) new(object['s'], object['o']) end
不帶任何引數時,傳回 $!
的值,這是最近模式比對的結果(請參閱 Regexp 全域變數)
/c(.)t/ =~ 'cat' # => 0 Regexp.last_match # => #<MatchData "cat" 1:"a"> /a/ =~ 'foo' # => nil Regexp.last_match # => nil
帶有非負整數引數 n
時,傳回比對資料中的第 _n_ 個欄位(如果有),否則傳回 nil
/c(.)t/ =~ 'cat' # => 0 Regexp.last_match(0) # => "cat" Regexp.last_match(1) # => "a" Regexp.last_match(2) # => nil
帶有負整數引數 n
時,從最後一個欄位開始往回計算
Regexp.last_match(-1) # => "a"
帶有字串或符號引數 name
時,傳回指定擷取的字串值(如果有)
/(?<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" Regexp.last_match('foo') # Raises IndexError.
static VALUE rb_reg_s_last_match(int argc, VALUE *argv, VALUE _) { if (rb_check_arity(argc, 0, 1) == 1) { VALUE match = rb_backref_get(); int n; if (NIL_P(match)) return Qnil; n = match_backref_number(match, argv[0]); return rb_reg_nth_match(n, match); } return match_getter(); }
如果針對 re
的比對可以在輸入字串中以線性時間執行,則傳回 true
。
Regexp.linear_time?(/re/) # => true
請注意,這是 ruby 解釋器的屬性,而不是引數正規表示式的屬性。相同的正規表示式可以或不能以線性時間執行,具體取決於您的 ruby 二進位檔。此方法的傳回值不保證向前或向後相容性。我們目前的演算法為 (*1),但這可能會在未來變更。其他實作也可能表現不同。它們可能會永遠對所有內容傳回 false。
(*1): doi.org/10.1109/SP40001.2021.00032
static VALUE rb_reg_s_linear_time_p(int argc, VALUE *argv, VALUE self) { struct reg_init_args args; VALUE re = reg_extract_args(argc, argv, &args); if (NIL_P(re)) { re = reg_init_args(rb_reg_alloc(), args.str, args.enc, args.flags); } return RBOOL(onig_check_linear_time(RREGEXP_PTR(re))); }
如果給定引數 字串
,則傳回一個包含給定字串和選項的新正規表示式
r = Regexp.new('foo') # => /foo/ r.source # => "foo" r.options # => 0
選用引數 選項
為下列其中之一
-
一個包含選項的
字串
Regexp.new('foo', 'i') # => /foo/i Regexp.new('foo', 'im') # => /foo/im
-
常數
Regexp::EXTENDED
、Regexp::IGNORECASE
、Regexp::MULTILINE
和Regexp::NOENCODING
中一個或多個的按位元 ORRegexp.new('foo', Regexp::IGNORECASE) # => /foo/i Regexp.new('foo', Regexp::EXTENDED) # => /foo/x Regexp.new('foo', Regexp::MULTILINE) # => /foo/m Regexp.new('foo', Regexp::NOENCODING) # => /foo/n flags = Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE Regexp.new('foo', flags) # => /foo/mix
-
nil
或false
,會略過。 -
任何其他真值,正規表示式將不區分大小寫。
如果給定選用關鍵字引數 timeout
,其浮點值會覆寫類別的超時間隔 Regexp.timeout
。如果傳入 nil
作為 +timeout,它會使用類別的超時間隔 Regexp.timeout
。
如果給定引數 正規表示式
,則傳回一個新的正規表示式。來源、選項和超時與 正規表示式
相同。選項
和 n_flag
引數無效。超時可以被 timeout
關鍵字覆寫。
options = Regexp::MULTILINE r = Regexp.new('foo', options, timeout: 1.1) # => /foo/m r2 = Regexp.new(r) # => /foo/m r2.timeout # => 1.1 r3 = Regexp.new(r, timeout: 3.14) # => /foo/m r3.timeout # => 3.14
static VALUE rb_reg_initialize_m(int argc, VALUE *argv, VALUE self) { struct reg_init_args args; VALUE re = reg_extract_args(argc, argv, &args); if (NIL_P(re)) { reg_init_args(self, args.str, args.enc, args.flags); } else { reg_copy(self, re); } set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout); return self; }
傳回一個新的字串,其中會跳脫正則表達式中具有特殊意義的任何字元
s = Regexp.escape('\*?{}.') # => "\\\\\\*\\?\\{\\}\\."
對於任何字串 s
,此呼叫會傳回一個 MatchData
物件
r = Regexp.new(Regexp.escape(s)) # => /\\\\\\\*\\\?\\\{\\\}\\\./ r.match(s) # => #<MatchData "\\\\\\*\\?\\{\\}\\.">
static VALUE rb_reg_s_quote(VALUE c, VALUE str) { return rb_reg_quote(reg_operand(str, TRUE)); }
它傳回 Regexp
匹配的目前預設超時間隔(單位為秒)。nil
表示沒有預設超時組態。
static VALUE rb_reg_s_timeout_get(VALUE dummy) { double d = hrtime2double(rb_reg_match_time_limit); if (d == 0.0) return Qnil; return DBL2NUM(d); }
它設定 Regexp
匹配的預設超時間隔(單位為秒)。nil
表示沒有預設超時組態。此組態是處理序全域的。如果您要為每個 Regexp
設定超時,請對 Regexp.new
使用 timeout
關鍵字。
Regexp.timeout = 1 /^a*b?a*$/ =~ "a" * 100000 + "x" #=> regexp match timeout (RuntimeError)
static VALUE rb_reg_s_timeout_set(VALUE dummy, VALUE timeout) { rb_ractor_ensure_main_ractor("can not access Regexp.timeout from non-main Ractors"); set_timeout(&rb_reg_match_time_limit, timeout); return timeout; }
如果 物件
是正規表示式,則傳回 物件
Regexp.try_convert(/re/) # => /re/
否則,如果 物件
對應到 :to_regexp
,則呼叫 object.to_regexp
並傳回結果。
如果物件不回應 :to_regexp
,則傳回 nil
。
Regexp.try_convert('re') # => nil
除非 object.to_regexp
傳回正規表示式,否則會引發例外狀況。
static VALUE rb_reg_s_try_convert(VALUE dummy, VALUE re) { return rb_check_regexp_type(re); }
傳回一個新的正規表示式,為給定樣式的聯集
r = Regexp.union(%w[cat dog]) # => /cat|dog/ r.match('cat') # => #<MatchData "cat"> r.match('dog') # => #<MatchData "dog"> r.match('cog') # => nil
對於每個字串樣式,會使用 Regexp.new(pattern)
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(/foo/i, /bar/m, /baz/x) # => /(?i-mx:foo)|(?m-ix:bar)|(?x-mi:baz)/ Regexp.union([/foo/i, /bar/m, /baz/x]) # => /(?i-mx:foo)|(?m-ix:bar)|(?x-mi:baz)/
如果沒有參數,則傳回 /(?!)/
Regexp.union # => /(?!)/
如果任何正規表示式樣式包含擷取,則行為未指定。
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); }
公開實例方法
如果 object
是另一個 Regexp,其樣式、旗標和編碼與 self
相同,則傳回 true
,否則傳回 false
/foo/ == Regexp.new('foo') # => true /foo/ == /foo/i # => false /foo/ == Regexp.new('food') # => false /foo/ == Regexp.new("abc".force_encoding("euc-jp")) # => false
如果 self
在 string
中找到相符項目,則傳回 true
/^[a-z]*$/ === 'HELLO' # => false /^[A-Z]*$/ === 'HELLO' # => true
此方法會在 case 陳述式中呼叫
s = 'HELLO' case s when /\A[a-z]*\z/; print "Lower case\n" when /\A[A-Z]*\z/; print "Upper case\n" else print "Mixed case\n" end # => "Upper case"
static 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); return RBOOL(start >= 0); }
傳回 self
和 string
的第一個相符項目的整數索引(以字元為單位),或如果沒有相符項目,則傳回 nil
;還會設定 rdoc-ref:Regexp 全域變數
/at/ =~ 'input data' # => 7 $~ # => #<MatchData "at"> /ax/ =~ 'input data' # => nil $~ # => nil
如果且僅當 self
是正規表示式文字時,將命名擷取指派給相同名稱的區域變數
-
請參閱正規表示式文字。
-
不包含內插;請參閱 正規表示式內插。
-
在表達式的左側。
範例
/(?<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
如果 self
不是正規表示式文字,則不會進行區域變數指派
r = /(?<foo>\w+)\s*=\s*(?<foo>\w+)/ r =~ ' x = y ' p foo # Undefined local variable p bar # Undefined local variable
如果正規表示式不在左側,則不會進行指派
' x = y ' =~ /(?<foo>\w+)\s*=\s*(?<foo>\w+)/ p foo, foo # Undefined local variables
正規表示式內插 #{}
也會停用指派
r = /(?<foo>\w+)/ /(?<foo>\w+)\s*=\s*#{r}/ =~ 'x = y' p foo # Undefined local variable
VALUE rb_reg_match(VALUE re, VALUE str) { long pos = reg_match_pos(re, &str, 0, NULL); if (pos < 0) return Qnil; pos = rb_str_sublen(str, pos); return LONG2FIX(pos); }
方法 Regexp#as_json
和 Regexp.json_create
可用於序列化和取消序列化 Regexp 物件;請參閱 Marshal
。
方法 Regexp#as_json
會序列化 self
,傳回一個表示 self
的 2 元素雜湊
require 'json/add/regexp' x = /foo/.as_json # => {"json_class"=>"Regexp", "o"=>0, "s"=>"foo"}
方法 JSON.create
會將此類雜湊反序列化,傳回一個 Regexp 物件
Regexp.json_create(x) # => /foo/
# File ext/json/lib/json/add/regexp.rb, line 28 def as_json(*) { JSON.create_id => self.class.name, 'o' => options, 's' => source, } end
如果 self
中設定了不區分大小寫標記,則傳回 true
,否則傳回 false
/a/.casefold? # => false /a/i.casefold? # => true /(?i:a)/.casefold? # => false
static VALUE rb_reg_casefold_p(VALUE re) { rb_reg_check(re); return RBOOL(RREGEXP_PTR(re)->options & ONIG_OPTION_IGNORECASE); }
傳回表示 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
適用於具有任何 ASCII 相容編碼的字串,則傳回 false
;否則傳回 true
r = /a/ # => /a/ r.fixed_encoding? # => false r.match?("\u{6666} a") # => true r.match?("\xa1\xa2 a".force_encoding("euc-jp")) # => true r.match?("abc".force_encoding("euc-jp")) # => true r = /a/u # => /a/ r.fixed_encoding? # => true r.match?("\u{6666} a") # => true r.match?("\xa1\xa2".force_encoding("euc-jp")) # Raises exception. r.match?("abc".force_encoding("euc-jp")) # => true r = /\u{6666}/ # => /\u{6666}/ r.fixed_encoding? # => true r.encoding # => #<Encoding:UTF-8> r.match?("\u{6666} a") # => true r.match?("\xa1\xa2".force_encoding("euc-jp")) # Raises exception. r.match?("abc".force_encoding("euc-jp")) # => false
static VALUE rb_reg_fixed_encoding_p(VALUE re) { return RBOOL(FL_TEST(re, KCODE_FIXED)); }
傳回 self
的整數雜湊值。
相關:Object#hash
。
VALUE rb_reg_hash(VALUE re) { st_index_t hashval = reg_hash(re); return ST2FIX(hashval); }
傳回 self
的格式良好的字串表示
/ab+c/ix.inspect # => "/ab+c/ix"
相關:Regexp#to_s
。
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(re); }
如果未提供區塊,則傳回描述匹配項(如果有的話)的 MatchData
物件,或如果沒有,則傳回 nil
;搜尋從 string
中指定的字元 offset
開始
/abra/.match('abracadabra') # => #<MatchData "abra"> /abra/.match('abracadabra', 4) # => #<MatchData "abra"> /abra/.match('abracadabra', 8) # => nil /abra/.match('abracadabra', 800) # => nil string = "\u{5d0 5d1 5e8 5d0}cadabra" /abra/.match(string, 7) #=> #<MatchData "abra"> /abra/.match(string, 8) #=> nil /abra/.match(string.b, 8) #=> #<MatchData "abra">
如果提供了區塊,則僅在找到匹配項時呼叫區塊;傳回區塊的值
/abra/.match('abracadabra') {|matchdata| p matchdata } # => #<MatchData "abra"> /abra/.match('abracadabra', 4) {|matchdata| p matchdata } # => #<MatchData "abra"> /abra/.match('abracadabra', 8) {|matchdata| p matchdata } # => nil /abra/.match('abracadabra', 8) {|marchdata| fail 'Cannot happen' } # => nil
輸出(來自上方前兩個區塊)
#<MatchData "abra"> #<MatchData "abra"> /(.)(.)(.)/.match("abc")[2] # => "b" /(.)(.)/.match("abc", 1)[2] # => "c"
static VALUE rb_reg_match_m(int argc, VALUE *argv, VALUE re) { VALUE result = Qnil, 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, &result); if (pos < 0) { rb_backref_set(Qnil); return Qnil; } rb_match_busy(result); if (!NIL_P(result) && rb_block_given_p()) { return rb_yield(result); } return result; }
傳回 true
或 false
以表示 regexp 是否匹配,而不更新 $~ 和其他相關變數。如果存在第二個參數,則它指定字串中開始搜尋的位置。
/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); }
傳回表示 self
的命名擷取的雜湊(請參閱 命名擷取)
-
每個鍵都是命名擷取的名稱。
-
每個值都是該命名擷取的整數索引陣列。
範例
/(?<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) { regex_t *reg = (rb_reg_check(re), RREGEXP_PTR(re)); VALUE hash = rb_hash_new_with_size(onig_number_of_names(reg)); onig_foreach_name(reg, reg_named_captures_iter, (void*)hash); return hash; }
傳回一個擷取名稱的陣列(請參閱 命名擷取)
/(?<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; }
傳回一個整數,其位元顯示在 self
中設定的選項。
選項位元為
Regexp::IGNORECASE # => 1 Regexp::EXTENDED # => 2 Regexp::MULTILINE # => 4
範例
/foo/.options # => 0 /foo/i.options # => 1 /foo/x.options # => 2 /foo/m.options # => 4 /foo/mix.options # => 7
請注意,傳回的整數中可能會設定其他位元;這些位元會在 self
內部維護,如果傳遞給 Regexp.new
則會略過,而且呼叫者可能會略過
傳回與建立此正規表示式時使用的選項對應的位元組(請參閱 Regexp::new
以取得詳細資料)。請注意,傳回的選項中可能會設定其他位元:這些位元由正規表示式程式碼在內部使用。如果選項傳遞給 Regexp::new
,這些額外的位元會略過
r = /\xa1\xa2/e # => /\xa1\xa2/ r.source # => "\\xa1\\xa2" r.options # => 16 Regexp.new(r.source, r.options) # => /\xa1\xa2/
static VALUE rb_reg_options_m(VALUE re) { int options = rb_reg_options(re); return INT2NUM(options); }
傳回 self
的原始字串
/ab+c/ix.source # => "ab+c"
Regexp
逸出序列會保留
/\x20\+/.source # => "\\x20\\+"
不會保留詞法分析器逸出字元
/\//.source # => "/"
static VALUE rb_reg_source(VALUE re) { VALUE str; rb_reg_check(re); str = rb_str_dup(RREGEXP_SRC(re)); return str; }
它傳回 Regexp
匹配的逾時區間(單位為秒)。nil
表示沒有預設逾時設定。
此設定是針對每個物件。如果設定每個物件的設定,Regexp.timeout=
設定的全球設定會略過。
re = Regexp.new("^a*b?a*$", timeout: 1) re.timeout #=> 1.0 re =~ "a" * 100000 + "x" #=> regexp match timeout (RuntimeError)
static VALUE rb_reg_timeout_get(VALUE re) { rb_reg_check(re); double d = hrtime2double(RREGEXP_PTR(re)->timelimit); if (d == 0.0) return Qnil; return DBL2NUM(d); }
傳回一個表示 self
的 JSON
字串
require 'json/add/regexp' puts /foo/.to_json
輸出
{"json_class":"Regexp","o":0,"s":"foo"}
# File ext/json/lib/json/add/regexp.rb, line 45 def to_json(*args) as_json.to_json(*args) end
傳回一個顯示 self
的選項和字串的字串
r0 = /ab+c/ix s0 = r0.to_s # => "(?ix-m:ab+c)"
傳回的字串可用作 Regexp.new
的引數,或作為 正規表示式內插 的內插文字
r1 = Regexp.new(s0) # => /(?ix-m:ab+c)/ r2 = /#{s0}/ # => /(?ix-m:ab+c)/
請注意,r1
和 r2
不等於 r0
,因為它們的原始字串不同
r0 == r1 # => false r0.source # => "ab+c" r1.source # => "(?ix-m:ab+c)"
相關:Regexp#inspect
。
static VALUE rb_reg_to_s(VALUE re) { return rb_reg_str_with_term(re, '/'); }
等同於 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); }