正則表達式在每種語言中都會有,目的就是匹配符合你預期要求的字符串。html
Python正則表達式主要由re庫提供,擁有了基本全部的表達式。前端
16.1 Python正則表達式python
符號git |
描述正則表達式 |
示例express |
. | 匹配除換行符(\n)以外的任意單個字符 | 字符串123\n456,匹配123:1.3 |
^ | 匹配字符串開頭 | abc\nxyz,匹配以abc開頭的行:^abc |
$ | 匹配字符串結尾 | abc\nxyz,匹配以xyz結束的行:xyz$ |
* | 匹配多個 | hello\nword,匹配以w開頭d結尾的單詞:w*d |
+ | 匹配1個或多個 | abc\nabcc\nadf,匹配abc和abcc:ab+ |
? | 匹配0個或1個 | abc\nac\nadd,匹配abc或ac:a?c |
[.] | 匹配中括號之中的任意一個字符 | abcd\nadd\nbbb,匹配abcd和add:[abc] |
[ .-.] | 匹配中括號中範圍內的任意一個字符 | abcd\nadd\nbbb,匹配abcd和add:[a-c] |
[^] | 匹配[^字符]以外的任意一個字符 | abc\n\abb\nddd,不匹配abc和abb:[^a-c] |
{n}或{n,} | 匹配花括號前面字符至少n個字符 | 1\n\12\n123\n1234,匹配123和1234:[0-9]{3} |
{n,m} | 匹配花括號前面字符至少n個字符,最多m個字符 | 1\n\12\n123\n1234\n12345,匹配123和1234 :[0-9]{3,4} |
| | 匹配豎槓兩邊的任意一個 | abc\nabd\abe,匹配abc和abd:ab(c|d) |
\ | 轉義符,將特殊符號轉成原有意義 | 1.2,匹配1.2:1\.2,不然112也會匹配到 |
特殊字符緩存 |
描述運維 |
示例ide |
\A | 匹配字符串開始 | 與^區別是:當使用修飾符re.M匹配多行時,\A將全部字符串做爲一整行處理。函數 abc123\nabc456,匹配abc123:\Aabc,^則都會匹配到 |
\Z | 匹配字符串結束 | 與\A同理 |
\b | 匹配字符串開始或結束(邊界) | abc\nabcd,匹配a開頭而且c結尾字符串:\babc\b |
\B | 與\b相反 | |
\d | 匹配任意十進制數,等效[0-9] | 1\n123\nabc,匹配1和123:[0-9],包含單個數字的都會匹配到,若是隻想匹配1:\b[0-9]\b |
\D | 匹配任意非數字字符,等效[^0-9] | 1\n12\nabc,匹配abc:[^0-9] |
\s | 匹配任意空白字符,等效[\t\n\r\f\v] | 1\n a,注意a前面有個空格,匹配a:\s |
\S | 匹配任意非空白字符,等效[^\t\n\r\f\v] | 1\n a\n ,匹配1和a:\S |
\w | 匹配任意數字和字母,等效[a-zA-Z0-9_] | 1\n a\n ,匹配1和a:\w |
\W | 與\w相反,等效[^a-zA-Z0-9_] | |
\n | 反向引用,n是數字,從1開始編號,表示引用第n個分組匹配的內容 | ff,匹配ff:(.)\1,即"ff" |
擴展正則表達式 |
描述 |
( ) | 匹配小括號中正則表達式或字符。用上面\n特殊字符引用。 |
(?#...) | 註釋小括號內的內容 |
(?:...) | 不保存匹配的分組 |
(?P<name>...) | 命名分組,name是標識名稱,默認是數字ID標識分組匹配 |
(?=...) | 匹配後面能匹配表的達式...,稱爲正先行斷言 |
(?!...) | 匹配後面不能匹配的表達式...,稱爲負先行斷言 |
(?<=...) | 匹配前面能匹配的表達式...,稱爲正後發斷言 |
(?<!...) | 匹配前面不能匹配的表達式...,稱爲負後發斷言 |
(?(id/name)Y/N) | 若是分組提供的id或name存在,則使用Y表達式匹配,不然N表達式匹配 |
斷言:斷言就是一個條件,判斷某個字符串前面或後面是否知足某種規律的字符串,不能引用。
16.2 re庫
re模塊有如下經常使用的方法:
方法 |
描述 |
re.compile(pattern, flags=0) | 把正則表達式編譯成一個對象 |
re.findall(pattern, string, flags=0) | 以列表形式返回全部匹配的字符串 |
re.finditer(pattern, string, flags=0) | 以迭代器形式返回全部匹配的字符串 |
re.match(pattern, string, flags=0) | 匹配字符串開始,若是不匹配返回None |
re.search(pattern, string, flags=0) | 掃描字符串尋找匹配,若是符合返回一個匹配對象並終止匹配,不然返回None |
re.split(pattern, string, maxsplit=0, flags=0) | 以匹配模式做爲分隔符,切分字符串爲列表 |
re.sub(pattern, repl, string, count=0, flags=0) | 字符串替換,repl替換匹配的字符串,repl能夠是一個函數 |
re.purge() | 清除正則表達式緩存 |
參數說明:
pattern 正則表達式
string 要匹配的字符串
flags 標誌位的修飾符,用於控制表達式匹配模式
標誌位的修飾符,有如下可選項:
修飾符 |
描述 |
re.DEBUG | 顯示關於編譯正則的debug信息 |
re.I/re.IGNORECASE | 忽略大小寫 |
re.L/re.LOCALE | 本地化匹配,影響\w,\w,\b,\B,\s和\S |
re.M/re.MULTILINE | 多行匹配,影響^和$ |
re.S/re.DOTAIL | 匹配全部字符,包括換行符\n,若是沒這個標誌將匹配除了換行符 |
re.U/re.UNICODE | 根據unicode字符集解析字符。影響影響\w,\w,\b,\B,\d,\D,\s和\S |
re.X/re.VERBOSE | 容許編寫更好看、更可讀的正則表達式,也能夠在表達式添加註釋,下面會講到 |
博客地址:http://lizhenliang.blog.51cto.com
QQ羣:323779636(Shell/Python運維開發羣)
16.2.1 re.compile()
把正則表達式編譯成一個對象,方便再次調用:
>>> import re prog = re.compile(pattern) result = prog.match(string) 等效於 result = re.match(pattern, string) 例如:檢查字符串是否匹配 >>> def displaymatch(match): ... if match is None: ... return None ... return '<Match: %r, group=%r>' % (match.group(), match.groups()) ... >>> valid = re.compile(r"^[a-c1-3]{3}$") >>> displaymatch(valid.match("a1b")) # 可用 "<Match: 'a1b', group=()>" >>> displaymatch(valid.match("a1b2")) # 不可用 >>> displaymatch(valid.match("bbb")) # 可用 "<Match: 'bbb', group=()>"
16.2.1 match()
例如:判斷字符串開頭是否匹配字符 >>> m = re.match(r'hello', 'hello world') >>> print m # 匹配到字符串開頭是hello <_sre.SRE_Match object at 0x7f56d5634030> >>> m = re.match(r'world', 'hello world') >>> print m # 沒有匹配到 None
正則對象匹配方法:
1)group([group1, ...])
>>> m = re.match(r'(\w+) (\w+)', 'hello world') >>> m.group(0) # 所有組匹配 'hello world' >>> m.group(1) # 第一個括號子組 'hello' >>> m.group(2) # 第二個括號子組 'world' >>> m.group(1, 2) # 多個參數返回一個元組 ('hello', 'world') 經過分子重命名的名字來引用分組結果: >>> m = re.match(r'(?P<first_name>\w+) (?P<last_name>\w+)', 'hello world') >>> m.group('first_name') 'hello' >>> m.group('last_name') 'world' # 命名組也能夠引用他們的索引 >>> m.group(1) 'hello' >>> m.group(2) 'world'
若是一組匹配屢次,只有最後一個匹配:
>>> m = re.match(r"(..)+", "a1b2c3") >>> m.group(1) 'c3'
2)groups([default])
返回一個元組包含全部子組的匹配。
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632") >>> m.groups() ('24', '1632')
3)groupdict([default])
返回子組名字做爲鍵,匹配結果做爲值的字典。
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "hello world") >>> m.groupdict() {'first_name': 'hello', 'last_name': 'world'}
4)start()和end()
例如:去掉郵件地址的某字符
>>> email = "tony@163_126.com" >>> m = re.search(r"_126", email) >>> email[:m.start()] + email[m.end():] 'tony@163.com'
5)span()
以列表形式返回匹配索引開始和結束值:
>>> email = "tony@163_126.com" >>> m = re.search(r"_126", email) >>> m.span() (8, 12)
6)pos和endpos
返回字符串開始和結束索引值:
>>> email = "tony@163_126.com" >>> m = re.search(r"_126", email) >>> m.pos 0 >>> m.endpos 16
16.2.3 search()
search()方法也具有match()方法的正則對象匹配方法,區別是search()匹配到第一個後就返回並終止匹配。
例如:匹配第一個結果就返回
>>> m = re.search(r"c", "abcdefc") >>> m.group() 'c' >>> m.span() (2, 3)
16.2.4 split()
例如:以數字做爲分隔符拆分字符串
>>> m = re.split(r"\d+", "a1b2c3") >>> m ['a', 'b', 'c', ''] 16.2.4 sub()
例如:替換2016
>>> m = re.sub(r"\d+", "2017", "the year 2016") >>> m 'the year 2017'
例如:repl做爲一個函數
>>> def repl(m): ... return str(int(m.group('v')) * 2) ... >>> re.sub(r'(?P<v>\d+)', repl, "123abc") '246abc'
函數返回必須是一個字符串。
16.2.5 findall()和finditer()
例如:獲得全部匹配的數字
>>> text = "a1b2c3" >>> re.findall(r'\d+', text) ['1', '2', '3'] >>> for m in re.finditer(r'\d+', text): ... print m.group() ... 1 2 3
16.2.6 原始字符串符號"r"
上面所看到的(r"\d+")其中的r表明原始字符串,沒有它,每一個反斜槓'\'都必須再加一個反斜槓來轉義它。
例如,下面兩行代碼功能上是相同的:
>>> m = re.match(r"\W(.)\1\W", " ff ") >>> m.group() ' ff ' >>> m = re.match("\\W(.)\\1\\W", " ff ") >>> m.group() ' ff ' >>> m = re.match("\W(.)\1\W", " ff ") >>> m.group() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'NoneType' object has no attribute 'group'
\W匹配第一個和最後一個空字符,(.)匹配第一個f,\1引用前面(.)匹配的結果(仍是f),便是r"ff"
16.3 貪婪和非貪婪匹配
貪婪模式:儘量最多匹配
非貪婪模式,儘量最少匹配,通常在量詞(*、+)後面加個問號就是非貪婪模式。
# 貪婪匹配 >>> re.findall(r"<div>.*</div>", "<div>a</div><div>b</div><div>c</div>") ['<div>a</div><div>b</div><div>c</div>'] # 非貪婪匹配 >>> re.findall(r"<div>.*?</div>", "<div>a</div><div>b</div><div>c</div>") ['<div>a</div>', '<div>b</div>', '<div>c</div>'] >>> re.findall(r"a(\d+)", "a123b") ['123'] >>> re.findall(r"a(\d+?)", "a123b") ['1'] # 若是右邊有限定,非貪婪失效 >>> re.findall(r"a(\d+)b", "a123b") ['123'] >>> re.findall(r"a(\d+?)b", "a123b") ['123']
貪婪匹配是儘量的向右匹配,直到字符串結束。
非貪婪匹配是匹配知足後就結束。
16.3 瞭解擴展表達式
以一個字符串來學習斷言的用法:"A regular expression "
1)(?=...)
正先行斷言,匹配後面能匹配的表達式。
有兩個re字符串,只想匹配regular中的:
>>> re.findall(r"..(?=gular)", "A regular expression") ['re'] # 再向後匹配幾個字符說明匹配的regular中的。下面都會說明下,再也不註釋 >>> re.findall(r"(?=gular).{5}", "A regular expression") ['gular']
2)(?!...)
負先行斷言,匹配後面不能匹配表達式。
只想匹配expression中的re字符串,排除掉regular單詞:
>>> re.findall(r"re(?!g)", "A regular expression") ['re'] >>> re.findall(r"re(?!g).{5}", "A regular expression") ['ression']
3)(?<=...)
正向後行斷言,匹配前面能匹配表達式。
只想匹配單詞裏的re,排除開頭的re:
>>> re.findall(r"(?<=\w)re", "A regular expression") ['re'] >>> re.findall(r"(?<=\w)re.", "A regular expression") ['res']
在re前面有一個或多個字符,因此叫後行斷言,正則匹配是從前向後,當遇到斷言時,會再向字符串前端檢測已掃描的字符,相對於掃描方向是向後的。
4)(?<!...)
負向後行斷言,匹配前面不能匹配的表達式。
只想匹配開頭的re:
>>> re.findall(r"(?<!\w)re", "A regular expression") ['re'] >>> re.findall(r"(?<!\w)re.", "A regular expression") ['reg']
16.4 修飾符
re.VERBOSE上面說明可能你還不太明白,怎麼個更加可讀呢,這就來看看,下面兩個正則編譯等效:
>>> a = re.compile(r"""\d + # the integral part ... \. # the decimal point ... \d * # some fractional digits""", re.X) >>> b = re.compile(r"\d+\.\d*")
當你寫的正則很長的時候,能夠添加註釋。
Python正則表達式參考:https://docs.python.org/2/library/re.html