動機
超越NFA的regex,酷!!
從NFA開始
.
(任一字元): transition
|
: 分岔到兩個state
*
: loop 或是 直接跳到下一個state
+
: ..*
{n,}
: <pat><pat>..(重複n-1次)<pat>+
\b
: word boundry,可以把單字(字母與數字)從其他非單字字元的包圍中抽出來
re.findall(r'\b[0-9]+?\b',"~123 456* 567")
\B
: not word boundry,就是不是word boundry的字元
re.findall(r'\B[0-9]+\B',"~123 456* 567")
?
: 除了是0或1的外,還有一個用法是不要比對到底(Laziness),像.*
原本會把所有字元都吃掉,但變成.*?
後就不會試著全部match,而是只match可以過的部分,其他交給別的pattern
從NFA到PDA
group (ptr): 把比對到的東西放到regex engine的變數(stack)中 (<pat>)
named group: group多了名字 (?P<name><pat>)
non-capturing group: pattern不放到regex engine的變數(stack)中 (?:<pat>)
atomic group(Once-only Subexpression): 會cut的group (?><pat>)
這個需要例子,像是a(?>bc|b)c
去比對abbcdabcc
會先match到ab
剩下的pattern是c
剩下的string是dabcc
,這會失敗,所以會retry
但,因為atomic group會cut,他會把已經比對過的string都忘掉,所以接下去是從bcdabcc
,
最後match到abcc
back reference: 透過變數使用之前比對到的東西來比對 \n
re.search(r'(hello) \1 \S+', 'This is a hello hello world!')
re.search(r'(\'|\").*\1',"\"This is a \'string\'\"")
從PDA到Turing Machine
lookahead: 先往後(右)看如果match才繼續下去(如果是negtive,就是不match才繼續下去) (?=<pat>) (?!<pat>)
lookbehind: 先往前(左)看如果match才繼續下去(如果是negtive,就是不match才繼續下去) (?<=<pat>) (?<!<pat>)
re.search(r'(?<=cda).*(?=c)','abbcdabcc')
re.search(r'(?=cda).*','abbcdabcc')
Recursion: 再複製一次pattern,再跑一次match,在Turing Machine可以當成把指針移到pattern的開頭 ?n OR ?R
regex.search(r"^(\((?1)*\))(?1)*$", "()()")
regex.search(r"(\w)((?R)|(\w?))\1", "kayak")
還有condition,但暫時搞不懂怎麼用,先放著
Ref
great cheatsheet concepts in advanced regex Recursive Regular Expression