正則表達式作為一種最常用的工具,在平常的工作中使用的非常普遍,在python中是由re庫提供這個功能,除此之外還有regex庫提供額外的功能。
在一般的正則表達式介紹中都是以ascii為代表來介紹的,但是作為一個中國的程序員,所遇到的一個最基本的問題就是字符編碼了。所以這里說下如何在python中匹配
非ascii字符。
正則表達式是使用一個模式串來找出所有可以用模式串描述的字符串,模式串由普通字符跟元字符組成,這就是正則表達式最核心的想法。在一個模式串中,
普通字符是用於匹配,而元字符則可以看成是在普通字符上的施加的一種操作或者是函數。既然如此,非ascii字符對正則表達式的影響就集中在普通字符這一塊而不是
元字符。而普通字符是由整數值表示的,匹配則意味着在模式串中的整數值跟在目標串中的整數值相等,如果在目標串跟模式串中使用了不同的字符編碼,很明顯,他
們是不能匹配的。因此在使用正則表達式用於匹配非ascii字符時,需要保持模式串跟目標串的編碼一致。如下所示:
當模式串的字符編碼跟目標串一致的時候就能夠成功的匹配。如果你的模式串中只有普通字符,那么這樣就可以滿足你的要求了。但是問題沒有這么簡單,當你試圖用元字符的時候就會出現問題,示例如下:
這里我們的模式串是'人生{2,}',想要匹配的字符串是有一個“人”和至少兩個“生”,但是從匹配的結果來看,這個正則表達式並沒有達到我們的目的。問題還是在於編碼,'人生{2,}'的GB18030編碼是'\xc8\xcb\xc9\xfa{2,}',因此這個正則表達式的意思就是匹配至少一個'\xc8\xcb\xc9'和至少兩個'\xfa',和我們表達的意思完全按不同,原因在於一個漢字字符使用了多個字節的表示,而元字符+只作用在最后一個字節上。對於這種問題的解決方案也很簡單,就是尋找一個能夠將漢字字符表示為數字的編碼,而不是使用多個數字來組合表示,也就是一種內部統一的表示。但是我現在又想到了一個問題,任何一個字符編碼最終都是一個字節一個字節的,因為計算機最基本的存儲單位就是字節,所以這個問題在於字符串比較函數的問題,沒有辦法將多個相關的字節識別成一個整體,才導致這個問題的。然后我們看到如果使用python內部的字符表示,那么就沒有什么問題!
在這里使用Unicode能夠解決問題,但是Unicode帶來的編碼卻不止於此,因為如果把可以識別的字符從ASCII擴大到Unicode,那么有些表示就需要重新定義了,比如\d,\w,\s等等。這里就以\w為例來演示Unicode的影響。
這里(?u)就是啟用Unicode dependent特性,可以看到在未啟用這個特性之前,使用正則表達式\w+不能匹配到任何的字符串,但是使用這個特性,那么就可以匹配到全部的漢字。其實在Unicode中,每個字符除了對應一個碼點(也就是一個數字),還有對應的屬性,可以在正則表達式中使用屬性來進行匹配,比如屬性為漢字什么的,還是很方便的。