首次接觸正則表達式是在工作中接觸到ruby語言腳本開發的時候,鑒於工作中經常需要對reply內容中的相關字段進行提取和比較,正則表達式就成為必須掌握的,但僅僅了解正則表達式的基本規則還不能完成上面說的這個工作,我們還需要了解跟這個密切相關的另外兩個概念:就是模式匹配和捕獲,因為此為自學摸索,如果表述錯誤或者失當的地方,請各位大佬指正:
正則表達式是用來匹配字符串的,字符串匹配成功后,我們還可以根據需求取其中的某個或者是某幾個子字符串(捕獲)進行其他的操作。下面先來介紹一下正則表達式的語法:
字符 . \ [...]
預定義字符集 \d \D \s \S \w \W
數量詞 * + ? {m} {m,n}
邊界匹配 ^ $ \A \Z \b \B
邏輯分組 | (....) (?P<name> ...) \<name> (?P<name>)
特殊構造 (?:...) (?iLmsux) (?#...) (?=...) (?!...) (?<=...) (?<!...) (?(id/name)yes_pattern|no_parttern)
語法 |
說明 |
表達式實例 |
匹配字符串 |
字符 |
|||
. | 匹配除換行"\n"外的任意字符串 | abc | abc |
\ | 轉義字符,使后一個字符改變原來的意思 | a\\c | a\c |
[...] | 字符集,對應的位置可以是字符集中任意字符,字符集中的字符可以逐個列出,也可以給出范圍,如[abc]或[a-c]。第一個字符如果是^則表示取反,如[^abc]表示不是abc中的其他字符。所有的特殊的字符在字符集中都失去其原有的特殊含義。在字符集中使用^、]或-,可以使用轉義字符匹配它們 | a[bcd]e | abe ace ade |
預定義字符集 |
|||
\d | 數字:[0-9] | a\dc | a1c |
\D | 非數字:[^0-9] | a\Dc | abc |
\s | 空白字符:[<空格>\t\r\n\f\v] | a\sc | a c |
\S | 非空白字符:[^\s] | a\Sc | abc |
\w | 單詞字符:[a-zA-z0-9_] | a\wc | abc |
\W | 非單詞字符:[^\w] | a\Wc | a c |
數量詞 |
|||
* | 匹配一個字符串0或無限次 | abc* | ab abc abccc |
+ | 匹配一個字符串1次或無限次 | abc+ | abc abccc |
? | 匹配一個字符串0次或1次 | abc? |
ab abc |
{m} | 匹配一個字符串m次 | abc{2} | abcc |
{m,n} | 匹配一個字符串m到n次 | abc{2,3} | abcc abccc |
邊界匹配 |
|||
^ | 匹配字符串開頭 | ^abc | abc |
$ | 匹配字符串末尾 | abc$ | abc |
\A | 匹配字符串開始 | \Aabc | abc |
\Z | 匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串 | abc\Z | abc |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 | ||
\B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 | ||
邏輯分組 |
|||
| | 匹配|表達式左右的任意一個 | abc|def | abc def |
(...) | 作為分組,每遇到一個(,分組編號加1,使用分組的好處是匹配的子串會保存到一個子組,便於以后使用 | (abc){2} | abcabc |
(?P<name>...) | 分組除原有編號外,再加一個別名 | (?P<id>abc){2} | abcabc |
\<number> | 引用編號為number的分組匹配到的字符串 | (\d)ab\1 | 1ab1 5ab5 |
(?P=name) | 應用別名為name的分組匹配到的字符串 | (?P<id>abc)ee(?P=name) | abceeabc |
特殊構造(不分組) |
|||
(?:...) | (...)的不分組版本,用於|或后接數量詞 | (?:abc){2} | abcabc |
(?iLmsux) | iLmsux中的每個字符代表正則表達式的一種匹配模式,只能用在正則表達式開頭,可選多個 | (?i)abc | AbC |
(?#...) | 將#后面的字符當做注釋忽略 | abc(?#comment)def | abcdef |
(?=...) | 之后的字符串表達式需要匹配才能成功,不消耗字符串內容 | a(?=\d) | 后面是數字的a |
(?!...) | 之后的字符串表達式需要不匹配才能成功,不消耗字符串內容 | a(?!\d) | 后面不是數字的a |
(?<=...) | 之前的字符串表達式需要匹配才能成功,不消耗字符串內容 | (?<=\d)a | 前面是數字的a |
(?<!...) | 之前的字符串表達式需要不匹配才能成功,不消耗字符串內容 | (?<!\d)a | 前面不是數字的a |
(?(id/name)yes_ pattern|no_parttern) |
如果匹配到分組為id或別名name的字符串成功匹配,則需要匹配yes_pattern 不成功,怎需要匹配no_pattern |
(\d)abc(?(1)\d|def) | 1abc3 abcdef |
修飾符中 i 當匹配文本的時候忽略大小寫
o 只執行一次#{}插值,正則表達式在第一次時就進行判斷
x 忽略空格,允許在整個表達式中放入空白符和注釋。
m 匹配多行,把換行字符識別為正常字符。
u,e,s,n 把正則表達式解釋為Unicode(utf-8)、EUC、SJIS或ASCII。如果沒有指定修飾符,則認為正則表達式使用的源編碼。
貪婪模式和非貪婪模式
貪婪模式是盡可能多的匹配字符串,python默認為貪婪模式,非貪婪模式盡可能少的匹配字符串,在正則表達式后面加個?表示非貪婪模式。例如:字符串abcccb,貪婪模式正則表達式為ab.*c,非貪婪模式的正則表達式為ab.*?c,貪婪模式結果為abccc,非貪婪模式結果為abc,再比如字符串abbb,貪婪模式正則表達式為ab?,非貪婪模式正則表達為ab??,貪婪模式結果為ab,非貪婪結果為a。
在ruby中,正則表達式是一種介於斜杠之間或者介於%r后的任意分隔符之間的模式,以下面的郵件頭信息為例:
Date: Tue, 30 Jul 2013 16:53:17 +0800
From: =?UTF-8?B?YmFpZHU=?=<passport@baidu.com>
To: =?UTF-8?B?aG9uZ3RlbnpvbmVAZm94bWFpbC5jb20=?=<hongtenzone@foxmail.com>
Subject: =?UTF-8?B?55m+5bqm5LqR6YCB5L2gMTAwR+WtmOWCqOepuumXtOmAmuefpQ==?=
MIME-Version: 1.0
Content-Type: text/html;
charset="UTF-8"
Content-Transfer-Encoding: base64
首先,將上述信息賦值給變量str,則str =~ /Date:.*/將匹配到Date整行;
也可寫成str =~ %r!Date:.*!
上面的表達方式比較粗糙,為了更精細的匹配可以寫成下面的格式:
str =~ /Date:\s\w+,\d+\s\w+\s\d+\s\d+:\d+:\d+\s\d++\d+/
Python的正則表達式的模塊是‘re’,例如在字符串s中找字符串a,則可以寫成
import re
s='asdf125'
re.findall(r'df',s)
Out[5]: ['df']
這里用到函數findall(rule,target[,flag])
同理,re.findall(r!Date:.*!,str)可以匹配到發件時間信息;
re.findall(r[From:.*],str)可以匹配到發件人信息;
在上面的例子中我們發現python通過findall函數返回的是符合模式的字符串內容,那如果我們想獲取符合模式的相關信息的內容,該怎么辦呢?那就用到捕獲:
str =~ /Date:\s(\w+),(\d+)\s(\w+)\s\d+\s\d+:\d+:\d+\s\d++\d+/
如上,如果我們print $1,$2,$3,則會對應輸出 Tue 30 Jul三個信息
python的表達和返回則如下:是一個元素類型為元組的列表。
re.findall(r'Date:\s(.*)(\d+):(\d+):(\d+).*', str)
Out[9]: [('Tue, 30 Jul 2013 1', '6', '53', '17')]
要想取出齊總的元素,可以用:
result = re.findall(r'Date:\s(.*)(\d+):(\d+):(\d+).*', str)
print(result[0][0])\print(result[0][1])...