python3: 字串和文字(2)

阿里瓜瓜發表於2019-01-29

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. 多行匹配模式

Q: 你正在試著使用正規表示式去匹配一大塊的文字,而你需要跨越多行去匹配。

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數字字元了

混合使用Unicode和正規表示式通常會讓你抓狂。 如果你真的打算這樣做的話,最好考慮下安裝第三方正則式庫, 它們會為Unicode的大小寫轉換和其他大量有趣特性提供全面的支援,包括模糊匹配。

 

 

相關文章