6. 字串忽略大小寫的搜尋替換
>>> text = 'UPPER PYTHON, lower python, Mixed Python' >>> re.findall('python', text, flags=re.IGNORECASE) ['PYTHON', 'python', 'Python'] >>> re.sub('python', 'snake', text, flags=re.IGNORECASE) 'UPPER snake, lower snake, Mixed snake' >>>
7.最短匹配(?)
Q: 你正在試著用正規表示式匹配某個文字模式,但是它找到的是模式的最長可能匹配。 而你想修改它變成查詢最短的可能匹配。
S:這個問題一般出現在需要匹配一對分隔符之間的文字的時候(比如引號包含的字串)。 為了說明清楚,考慮如下的例子:模式 r'\"(.*)\"'
的意圖是匹配被雙引號包含的文字。(.)匹配除了換行外的任何字元
>>> str_pat = re.compile(r'"(.*)"') >>> text1 = 'Computer says "no."' >>> str_pat.findall(text1) ['no.'] >>> text2 = 'Computer says "no." Phone says "yes."' >>> str_pat.findall(text2) ['no." Phone says "yes.']
第二個例子中搜尋 text2
的時候返回結果並不是我們想要的。
為了修正這個問題,可以在模式中的*操作符後面加上?修飾符,就像這樣:
>>> str_pat = re.compile(r'"(.*?)"') >>> str_pat.findall(text2) ['no.', 'yes.'] >>>
通過在 *
或者 +
這樣的操作符後面新增一個 ?
可以強制匹配演算法改成尋找最短的可能匹配。
8. 多行匹配模式
S:這個問題很典型的出現在當你用點(.)去匹配任意字元的時候,忘記了點(.)不能匹配換行符的事實。 比如,假設你想試著去匹配C語言分割的註釋:
>>> comment = re.compile(r'/\*(.*?)\*/') >>> text1 = '/* this is a comment */' >>> text2 = '''/* this is a ... multiline comment */ ... ''' >>> >>> comment.findall(text1) [' this is a comment '] >>> comment.findall(text2) [] >>>
為了修正這個問題,你可以修改模式字串,增加對換行的支援。比如:
#(?:.|\n)
指定了一個非捕獲組 (也就是它定義了一個僅僅用來做匹配,而不能通過單獨捕獲或者編號的組)
>>> comment = re.compile(r'/\*((?:.|\n)*?)\*/') >>> comment.findall(text2) [' this is a\n multiline comment '] >>>
(?:x)
匹配 'x' 但是不記住匹配項。這種叫作非捕獲括號,使得你能夠定義為與正規表示式運算子一起使用的子表示式。來看示例表示式 /(?:foo){1,2}/。如果表示式是 /foo{1,2}/,{1,2}將只對 ‘foo’ 的最後一個字元 ’o‘ 生效。如果使用非捕獲括號,則{1,2}會匹配整個 ‘foo’ 單詞。
re.compile()
函式接受一個標誌引數叫 re.DOTALL
,在這裡非常有用。 它可以讓正規表示式中的點(.)匹配包括換行符在內的任意字元。比如:
>>> comment = re.compile(r'/\*(.*?)\*/', re.DOTALL) >>> comment.findall(text2) [' this is a\n multiline comment ']
9. 將Unicode文字標準化
>>> s1 = 'Spicy Jalape\u00f1o' >>> s2 = 'Spicy Jalapen\u0303o' >>> s1 'Spicy Jalapeño' >>> s2 'Spicy Jalapeño' >>> s1 == s2 False >>> len(s1) 14 >>> len(s2) 15 import unicodedata >>> t1 = unicodedata.normalize('NFC', s1) >>> t2 = unicodedata.normalize('NFC', s2) >>> t1 == t2 True >>> print(ascii(t1)) 'Spicy Jalape\xf1o' >>> t3 = unicodedata.normalize('NFD', s1) >>> t4 = unicodedata.normalize('NFD', s2) >>> t3 == t4 True >>> print(ascii(t3)) 'Spicy Jalapen\u0303o' >>>
NFC表示字元應該是整體組成(比如可能的話就使用單一編碼),而NFD表示字元應該分解為多個組合字元表示。Python同樣支援擴充套件的標準化形式NFKC和NFKD
10. 在正則式中使用Unicode
re
模組已經對一些Unicode字元類有了基本的支援。 比如, \\d
已經匹配任意的unicode數字字元了