[Python] 串接正規表示式 (regular expression) 的問題
今天遇到一個奇怪的正規表示法 (regular expression) 的問題…
專案程式裡面為了方便,定義了一些簡單的 regular expression 的字串,
再用這些簡單的字串組成比較複雜的定義~
舉例來說,下面的程式定義了 letters 和 digits 兩個正規表示式,
接著用 | 把這兩個表示式連接起來變成 letters_and_digits,
表示只要符合 letters 或是 digits 的表示法都可以:
import re letters = r'[a-zA-Z]+' digits = r'\d+' letters_and_digits = r'(?:letters)|(?:digits)'.replace('letters', letters).replace('digits', digits) regex = re.compile("^%s$" % (letters_and_digits)) print regex.match("123") print regex.match("abc") print regex.match("abc123")
預期的結果是 123 是屬於 digits,abc 是屬於 letters,所以應該都是 True,
而 abc123 應該不能符合 (因為我們有指定 ^ 和 $,預期是要整個字串都符合 letters 或是都符合 digits),
但結果卻出人意料~三個敘述的結果都是 True,是怎麼一回事呢?
仔細看了一下,原來我們加上 ^ 和 $ 的方法有問題,
上面的寫法會變成有點像是下面這樣 (省略了 replace 的部分):
regex = re.compile("^(?:letters)|(?:digits)$")
這個正規表示法的意思,是開頭要符合 letters、或者是以 digits 結尾,
如果再使用 match() 的話,會強制從字串的最開頭開始比對,
因此就是要開頭要符合 letters、或是開頭到結尾都是 digits~
這樣就能解釋為什麼 “abc123” 會符合了,因為它的開頭 abc 是符合 letters 的~
要解決這個問題,在前面都加上 () 包住正規表示式後,再加上 ^ 和 $ 就行了,
也就是把 re.compile 那行改成:
regex = re.compile("^(%s)$" % (letters_and_digits))
結論:正規表示法雖然可以串接,但是要很小心呀~~
參考資料:python: re.match()
(本頁面已被瀏覽過 1,457 次)
4 thoughts on “[Python] 串接正規表示式 (regular expression) 的問題”
有關 Python 『 re 』使用疑問 『 搞不懂 r 作用是什麼 』
從妳所寫的這一篇『 [Python] 串接正規表示式 (regular expression) 的問題 』
內文中有看到
letters = r'[a-zA-Z]+’
digits = r’\d+’
letters_and_digits = r'(?:letters)|(?:digits)’.replace(‘letters’, letters).replace(‘digits’, digits)
在 『 參考資料:python: re.match() 』
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*”)
主要是為了減少 escape 的問題…
例如,假設我想要搜尋 bot 這個字,
並且確保它是一個完整的字,而不是像 robot 這種,
我可以用 \bbot\b,
因為 \b 在正規表示法裡,是代表 word boundary 的意思。
但如果你寫 “\bbot\b”,python 會認為 \b 是代表 ASCII 的 backspace
(類似 \r, \n 這些字元都有特殊意義),
所以你就得寫成 “\\\bbot\\\b”,不太方便。
用 r”\bbot\b” 的話,就不需要再 escape \ 了。
收到
,學 CODE ,真的需要 有 先行者 幫忙
,就如我原本發問
,找了很久也沒找到 『escape 』這樣的使用解釋 ;
放著不管 也不是 ,又不曉得 是否這就是 必須這麼使用 -_-
謝謝妳。
不客氣 🙂