正則表達式
下面就來講講ruby支持的正則表達式符號(元字符)。
有這么個規則:
- 不帶\的數字和字母不是元字符
- 帶\的符號也不是元字符
下文中出現的“匹配多字節字符的正則表達式”是指,通過使用 $KCODE 進行設定,或顯式地使用漢字選項(請參考 正則表達式字面值 )等方式進行的匹配多字節字符的正則表達式。
-
^
行首。與字符串的頭部或換行符之后的位置相匹配。
-
$
行尾。與字符串的尾部或換行符之前的位置相匹配。不包括換行符本身。
ruby 1.8 特性 :以前,只匹配字符串尾部換行符前的位置,現在則擴大到字符串的尾部。 trap::Regexp
p "\n".gsub(/$/, "o") => "o\n" (1.6) => "o\no" (1.8)
-
.
匹配除換行符以外的任意一個字符。使用正則表達式選項 m(多行模式。請參考 正則表達式字面值 ) 時,則匹配包括換行符在內的任意一個字符。在匹配多字節字符的正則表達式中,則匹配一個字(非單字節)。
當遇到不完整的多字節字符的一部分(無法判斷該字符是多字節字符?二進制?還是ASCII)時,也不會匹配。
p /./e =~ "あ"[0,1] # => nil
-
\w
字母和數字。等同于
[0-9A-Za-z]
。若為匹配多字節字符的正則表達式時,則也會匹配日語的全角字符。
-
\W
非字母和數字。
\w
以外的單個字符。 -
\s
空字符。相當于
[ \t\n\r\f]
-
\S
非空字符。
[ \t\n\r\f]
以外的單個字符。 -
\d
數字。即
[0-9]
-
\D
非數字
-
\A
字符串頭部。與
^
不同的是,它不受有無換行符的影響 。 -
\Z
字符串尾部。若字符串以換行符結尾,則匹配換行符前的位置。
ruby 1.8 特性 :以前,只匹配字符串尾部換行符前的位置,現在則擴大到字符串的尾部。 trap::Regexp
p "\n".gsub(/\Z/, "o") => "o\n" (1.6) => "o\no" (1.8)
-
\z
字符串結尾。與$以及\Z不同的是,它不受有無換行符的影響。
-
\b
在字符范圍描述符之外時表示詞邊界(匹配從\w到\W)。在字符范圍描述符之內時表示退格符(0x08)。
-
\B
非詞邊界
-
\G
在上次成功匹配的地方(之后)進行匹配(不留余地)。只有在首次使用時才會匹配到頭部(與\A相同)。
可以用在 scan 和 gsub 中。當您想在上次匹配的地方之后再進行匹配的話,可以使用。
舉個簡單(沒什么用)的例子。
# 從頭取出3位數字(數字必須相連)。 str = "123456 789" str.scan(/\G\d\d\d/) {|m| p m }
-
[ ]
指定字符范圍。請參考 字符范圍
。
-
*
前面元素至少出現0次。盡可能匹配較長的部分。
-
*?
負責指定數量(quantifiers)。表示前面元素至少出現0次(盡量匹配短的部分)
-
+
負責指定數量(quantifiers)。表示前面元素至少出現1次
-
+?
負責指定數量(quantifiers)。表示前面元素至少出現1次(盡量匹配短的部分)
-
{m}
-
{m,}
-
{m,n}
指定元素重復出現的次數(interval quantifier)。分別表示前面元素重復出現
- m 次
- 至少 m 次
- 至少 m 次,至多 n 次
{,n}
或{,}
將導致匹配失敗。str = "foofoofoo" p str[/(foo){1}/] # => "foo" p str[/(foo){2,}/] # => "foofoofoo" p str[/(foo){1,2}/] # => "foofoo"
正則表達式
?
,*
,+
分別等同于{0,1}
,{0,}
{1,}
。 -
{m}?
-
{m,}?
-
{m,n}?
指定元素重復出現的次數(interval quantifier)。分別表示前面元素重復出現
- m 次
- 至少 m 次
- 至少 m 次,至多 n 次
(盡量匹配短的部分)。
-
?
負責指定數量(quantifiers)。表示前面元素至多出現1次。
-
??
負責指定數量(quantifiers)。表示前面元素至多出現1次(盡量匹配短的部分)
-
|
選擇(alternative)。
-
( )
正則表達式的群組化。與括號中的正則表達式相匹配的字符串將被保存下來,供后方參考使用。
-
\1
,\2
...\ n
后方參考(back reference)。請參考 后方參考 。
-
(?# )
注釋。括號中的任意字符串將被忽視。
-
(?: )
不具備后方參考功能的群組化。它不為\1,\2(或 $1 , $2 )提供服務,是一種單純的群組功能。
/(abc)/ =~ "abc" p $1 => "abc" /(?:abc)/ =~ "abc" p $1 => nil
-
(?= )
先行(lookahead)。使用模式(pattern)指定位置(不留間隔)
(?=re1)re2
表示將匹配同時符合re1和re2的要求的字符串。
re1(?=re2)
という山附は、稿に re2 とマッチする矢機誤が魯く、正則表達式 re1 です。
p /foo(?=bar)/ =~ "foobar" # => 0 p $& # => "foo" (bar の嬸尸の攫鼠はない)
-
(?! )
否定先行(negative lookahead)。使用否定的模式(pattern)來指定位置(不留間隔)
(?!re1)re2
該正則表達式表示,匹配re1但不匹配re2。
# 除000以外的3位數字 re = /(?!000)\d\d\d/ p re =~ "000" # => nil p re =~ "012" # => 0 p re =~ "123" # => 0 # C語言標識符 (首位是[A-Za-z_]然后是[0-9A-Za-z_]的字符串) /\b(?![0-9])\w+\b/
-
(?> )
禁用 回縮功能 。
該功能尚處于試驗階段。將來有可能被停用,請您注意使用。特別是不要在廣義庫中使用。
-
(?ixm-ixm)
正則表達式中的i選項、x選項、m選項的開關。請您參考 正則表達式字面值 來了解選項的詳細內容。
re = /A(?i)a(?-i)A/ p re =~ "AaA" # => 0 p re =~ "AAA" # => 0 p re =~ "AAa" # => nil
-
(?ixm-ixm: )
括號中的i選項、x選項、m選項的開關。在括號范圍內有效。
re = /A(?i:a)A/ p re =~ "AaA" # => 0 p re =~ "AAA" # => 0 p re =~ "AAa" # => nil
后方參考
正則表達式 \1 \2 ... \n 表示后方參考。\n表示將匹配第n個括號(正則表達式的()表示群)的內容保存起來,供后面使用。
/((foo)bar)\1\2/
和
/((foo)bar)foobarfoo/
是一樣的。
例:
re = /(foo|bar|baz)\1/ p re =~ 'foofoo' # => 0 p re =~ 'barbar' # => 0 p re =~ 'bazbaz' # => 0 p re =~ 'foobar' # => nil
對應的括號必須位于后方參考表達式的左側。
若后方參考表達式位于對應的括號中時,匹配常常會失敗。當后方參考表達式中的數字是1位,且沒有對應的括號時,匹配也將失敗。
p /(\1)/ =~ "foofoofoo" # => nil p /(foo)\2/ =~ "foo\2" # => nil
雖然可以指定2位以上的后方參考表達式,但是不要把它同 反斜線表示法 的\nnn(對應于8進制數nnn的字符)混為一談。當數字只有1位時,通常是后方參考表達式。當指定了一個超過2位的數字時,若沒有對應括號的話,則被看作是8進制代碼。
相反地,若在正則表達式中使用1位的8進制代碼時,必須以0打頭,例如\01等(不可能存在形如\0這樣的后方參考表達式,因此不會混淆)。
p /\1/ =~ "\1" # => nil # 無對應括號的后方參考 p /\01/ =~ "\1" # => 0 8 進制代碼 p /\11/ =~ "\11" # => 0 8 進制代碼 # 8 進制代碼 (因為沒有對應括號) p /(.)\10/ =~ "1\10" # => 0 # 后方參考 (因為有對應的括號) p /((((((((((.))))))))))\10/ =~ "aa" # => 0 # 8 進制代碼 (因為沒有像"\0" + "8" -> \08 這樣的8進制代碼) p /(.)\08/ =~ "1\0008" # => 0 # 如果想在后方參考表達式之后插入數字的話,就必須使用括號加以分隔。 p /(.)(\1)1/ =~ "111" # => 0
字符范圍
正則表達式 [] 負責指定字符范圍。這將匹配 [] 內列出的任何一個字符。
例如/[abc]/表示只要匹配"a", "b", "c"中任何一個即可。也可以按照ASCII代碼順序,在連續的字符串之間插入“-”后寫成/[a-c]/也是一樣的效果。另外,若頭上是“^”的話,表示要匹配指定字符之外的一個字符。
若“^”不在頭上的話,表示匹配該字符本身。同時,當“-”出現在頭或尾上時,表示匹配該字符本身。
p /[a^]/ =~ "^" # => 0 p /[-a]/ =~ "-" # => 0 p /[a-]/ =~ "-" # => 0 p /[-]/ =~ "-" # => 0
空的字符范圍將引發錯誤。
p /[]/ =~ "" p /[^]/ =~ "^" # => invalid regular expression; empty character class: /[^]/
當“]”出現在頭上(或否定的“^”之后)時,表示“]”本身,而并非字符范圍的結尾。
p /[]]/ =~ "]" # => 0 p /[^]]/ =~ "]" # => nil
可以使用反斜線對"^", "-", "]" 以及 "\\"(反斜線)進行轉義,使其匹配該字符本身。
p /[\^]/ =~ "^" # => 0 p /[\-]/ =~ "-" # => 0 p /[\]]/ =~ "]" # => 0 p /[\\]/ =~ "\\" # => 0
在[]中可以使用 反斜線表示法 以及正則表達式\w, \W, \s, \S, \d, \D (這些都是表示字符范圍的簡寫法)。
請注意,下列包含否定意味的字符范圍也將匹配換行符(正則表達式 \W,\D 也是如此)。
p /[^a-z]/ =~ "\n" # => 0
字符范圍中也可以使用下列特殊的表達法,但是,將來這些表達法是否會繼續得到支持還未可知(所以此處從略,欲知詳情請參考 grep(1) 的手冊)。
[:alnum:] 數字和字母 0-9a-zA-Z [:alpha:] 字母 a-zA-Z [:blank:] 空白類 [:cntrl:] 控制字符 [:digit:] 數字 [:graph:] 除空白以外的可打印可視字符 [:lower:] 小寫字母 [:print:] 可視字符 [:punct:] 符號 [:space:] 空白字符 [:upper:] 大寫字母 [:xdigit:] 16進制字符
例: (包括"[]"在內,"[:...:]"表示1個字符。并非文字類的"[]")
p /[[:alnum:]][[:cntrl:]]/ =~ "a\x01" # => 0
注: 全角字符不在考慮范圍之內。即使指定讓正則表達式對漢字進行匹配時,[:alpha:]等也不會匹配全角的字母。
p /[[:alpha:]]/e =~ "A" # => nil
回縮(backtrack)
用特殊括號(?> )將正則表達式括起來后,與該正則表達式相匹配的字符串中的回縮功能就將失效。舉例如下。
例如在通常的正則表達式中
p /(a*)ab/ === 'aaab'
是匹配的。該匹配過程如下所示。
- 正則表達式 a* 從索引0開始匹配3個a
- 正則表達式 a 匹配失敗
- 正則表達式 a* 將匹配部分稍稍“縮小”一下,匹配2個a(使用了回縮功能)
- 正則表達式 a 與字符a匹配
- 正則表達式 b 與字符b匹配
- 正則表達式 a* 從索引0開始匹配3個a
- 正則表達式 a 匹配失敗
- a* 想把匹配部分回縮一下,但由于特殊括號的作用,回縮功能失效。
- 正則表達式 a* 從索引1開始匹配2個a
接下來的匹配都不成功,最終導致整體匹配失敗。
簡單說來,通常的正則表達式是“貪婪型的匹配”,而(?> )則是“超貪婪型的匹配”,因為它一旦匹配成功就決不放手。
范例
為了便于您拷貝使用,我們將其代入到以$re_開頭的全局變量中。
數值
-
浮點數(包括整數)
$re_float = /[-+]?(?:[0-9]+(\.[0-9]*)?|(\.[0-9]+))([eE][-+]?[0-9]+)?/ p $re_float =~ "1.23" # => 0 p $&.to_f # => 1.23 p $re_float =~ ".23" # => 0 p $&.to_f # => 0.23 p $re_float =~ "1.23e1" # => 0 p $&.to_f # => 12.3 p $re_float =~ "1.23e-1" # => 0 p $&.to_f # => 0.123
用逗號將數字劃分成3位一組的形式
-
方法1:使用回行和先行的方法(回行(lookbehind)需要Oniguruma庫的支持)
p "tone of 12345Hz".gsub(/(?<=\d)(?=(?:\d\d\d)+(?!\d))/, ',') => ruby 1.8.0 (2003-08-07) [i586-linux] "tone of 12,345Hz"
-
方法2:只使用先行的方法
p "tone of 12345Hz".gsub(/(\d)(?=(?:\d\d\d)+(?!\d))/, '\1,') => ruby 1.8.0 (2003-08-07) [i586-linux] "tone of 12,345Hz"
-
方法3:不使用先行的方法
s = "tone of 12345Hz" nil while s.gsub!(/(.*\d)(\d\d\d)/, '\1,\2') p s => ruby 1.8.0 (2003-08-07) [i586-linux] "tone of 12,345 Hz"
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
