2010-01-12 88 views
5

我正在閱讀一本書,它們提供瞭如何將給定字符串與正則表達式匹配的示例。 這裏是他們的榜樣:標準正則表達式與python正則表達式的差異

b*(abb*)*(a|∊) - Strings of a's and b's with no consecutive a's. 

現在我試着將其轉換到Python,像這樣:

>> p = re.compile(r'b*(abb*)*(a|)') # OR 
>> p = re.compile(r'b*(abb*)*(a|\b)') 

# BUT it still doesn't work 
>>> p.match('aa') 
<_sre.SRE_Match object at 0x7fd9ad028c68> 

我的問題是雙重的:

  1. 什麼是相當於python中的epsilon使上面的例子工作?
  2. 有人可以向我解釋爲什麼使用正則表達式的理論或標準方式在python中不起作用嗎?這可能與最長與最短匹配有關嗎?

澄清:對於人問什麼標準正則表達式是 - 它是形式語言理論標準:http://en.wikipedia.org/wiki/Regular_expression#Formal_language_theory

+1

的例子的評論是錯誤的...正則表達式做了和b的不僅匹配字符串沒有一個連續的。我會用b + btw代替bb *。 – 2010-01-12 14:56:02

+1

在這種情況下epsilon的預期行爲是什麼?我從來沒有見過,我已經編程了12年... – jathanism 2010-01-12 14:57:16

+2

「標準」正則表達式?誰定義了這個標準? ANSI? ISO? IEEE?我的天啊? – 2010-01-12 15:14:32

回答

5

感謝您的答案。我覺得每個答案都有答案的一部分。這是我正在尋找的東西。

  1. 符號只是(某事|ε)的簡寫。因此(a |ε)可以重寫爲a?。因此,例如變爲:

    b*(abb*)*a? 
    

    在Python中,我們可以這樣寫:

    p = re.compile(r'^b*(abb*)*a?$') 
    
  2. 正規正則表達式語法的原因,直接翻譯成蟒蛇(即複製和粘貼)不工作是因爲蟒蛇比賽最短的子串(如果符號$或^不存在),而理論正則表達式匹配最長的初始子串
    因此,例如,如果我們有一個字符串:

    s = 'aa' 
    

    我們的教材正則表達式B *(ABB *)*一個?不符合它,因爲它有兩個a。但是,如果我們直接將它複製到Python:

    >> p = re.compile(r'b*(abb*)*a?') 
    >> bool(p.match(s)) 
    True 
    

    這是因爲我們的正則表達式只有子我們的字符串的「A」「AA」相匹配。
    爲了告訴Python做我們告訴它開始和字符串的結尾是整個串的匹配,分別與^$符號:

    >> p = re.compile(r'^b*(abb*)*a?$') 
    >> bool(p.match(s)) 
    False 
    

    請注意,python正則表達式匹配()匹配開始的字符串,所以它在開始時自動假定爲^。但搜索()函數沒有,因此我們保留^
    因此,例如:

    >> s = 'aa' 
    >> p = re.compile(r'b*(abb*)*a?$') 
    >> bool(p.match(s)) 
    False     # Correct 
    >> bool(p.search(s)) 
    True     # Incorrect - search ignored the first 'a' 
    
+0

很好的總結了答案! – 2010-01-12 21:39:33

+0

「... python匹配最短的子字符串...」是錯誤的。它只是不一定匹配最長的子字符串,就像數學正確的正則表達式一樣。 – 2010-01-12 22:57:11

+0

@Alan:如果沒有提供^或$,它匹配最短的子字符串。 – drozzy 2010-01-16 21:49:24

3
  • 使用bool(p.match('aa'))檢查,如果正則表達式匹配或不

  • p = re.compile('b*(abb*)*a?$')

  • \b匹配字符串的邊框; \w\W(字字符和非單詞字符)

  • 之間

正則表達式是在python相當標準放置。然而,每種語言都有它們的味道,它們不是100%便攜式的。在使用任何特定語言的正則表達式之前,您需要查找的細微差異。

加成

\epsilon沒有在Python特殊符號。它是一個空字符集。

在您的示例中a|\epsilon相當於(a|)a?。之後$必須匹配字符串的結尾。

+0

我不認爲OP需要一個字邊界...你可以在一個字的中間使用epsilon ...它只是意味着空字符串... 另外,通過「標準」,我認爲OP意味着計算教科書理論中使用的一種正則表達式...沒有。或^ $或\ w或[1-9]或{3},但用\ epsilon,\ lambda等 – 2010-01-12 14:55:39

+0

我不確定你的意思是什麼「這就是爲什麼在書籍中他們發明了一些你期望的特殊字符在使用任何特定語言之前查找「。請澄清/重寫,我會接受。 – drozzy 2010-01-12 15:47:57

+0

這是一個快速猜測。自從我學習理論正則表達式以來,已經有很長一段時間了。刪除。忘記它:) – 2010-01-12 16:17:28

3

我並不確定python中的匹配是如何工作的,但我認爲你可能需要將^ .... $添加到你的RE中。 RegExp匹配通常匹配子字符串,並且在p.match('aa')是「a」(可能是第一個匹配)的情況下找到最大匹配。^... $確保你匹配了ENTIRE字符串,這是我相信你想要的。

理論/標準reg exps假定您總是匹配整個字符串,因爲您使用它來定義匹配的字符串語言,而不是在輸入字符串中找到子字符串。

+0

^在這裏沒有必要。這是在re.match中假定的。在重新研究中,這不是這兩者之間的唯一區別。 – 2010-01-12 14:52:57

+0

有趣的是$需要嗎?因爲如果它不是你的正則表達式需要...($ | $),否則它與任何東西匹配... – 2010-01-12 15:01:31

+0

'$'代表一個行結束,我不認爲這是你在找什麼。 're.match'的作用與'^'一樣(用於行開始)。 – jathanism 2010-01-12 15:08:55

1

由於您的正則表達式匹配任何樣本文本的任何零寬度段,因此您匹配。你需要anchor你的正則表達式。下面是做這件事,使用零寬度預測先行斷言的一種方式:

re.compile(r'^(a(?!a)|b)*$') 
5

實際上,例如工作得很好......一個小細節。我會寫:

>>> p = re.compile('b*(abb*)*a?') 
>>> m = p.match('aa') 
>>> print m.group(0) 
'a' 
>>> m = p.match('abbabbabababbabbbbbaaaaa') 
>>> print m.group(0) 
abbabbabababbabbbbba 

請注意,組0返回正則表達式匹配的字符串部分。如你所見,表達式匹配a和b的連續而不重複a。如果確實,要檢查整個字符串,你需要稍微改變:

>>> p = re.compile('^b*(abb*)*a?$') 
>>> m = p.match('aa') 
>>> print m 
None 

^$力識別字符串的開頭和結尾。

>>> len(m.group(0)) == len('aa') 

新增:

最後,您可以用第一個正則表達式,但最終測試結合這兩種方法對於OT的第二部分,在我看來有標準正則表達式和python實現之間沒有差異。當然,符號略有不同,python實現提供了一些擴展(像其他大多數包)。

+0

+1打我的答案! :)順便說一下'^'不是必須的,因爲re.match()只會在字符串的最開始處嘗試模式。 – 2010-01-12 15:11:00

+0

哦..你的例子是錯誤的。 'p = re.compile('b *(abb)* a?')'不匹配'aba' – 2010-01-12 15:14:58

+0

哎呀..剛剛在第一個正則表達式中忘了一顆星......正確! – PierreBdR 2010-01-12 15:17:52

1

你的第二個應該是一個適當的替代epsilon,盡我所知,儘管我從來沒有在正則表達式中使用過epsilon。

對於它的價值,你的模式匹配'a'。也就是說,它是匹配:

  • 零個或多個 「b 」S(選擇零)
  • 零個或多個「 (abb*) 」S(選擇零)
  • 一個「 a」 或字尾(選擇一個)。

喬納森範伯格指出,如果要確保整個字符串匹配,你必須錨定你的正則表達式的開頭('^')和結束('$')。每當在python中構造正則表達式時,您還應該使用原始字符串:r'my regex'。這將防止過度的反斜槓逃避混亂。

1

與表達問題是,它匹配空字符串,這意味着,如果你這樣做:

>>> p = re.compile('b*(abb*)*(a|)') 
>>> p.match('c').group(0) 
'' 

,自re.match試圖將字符串的開頭匹配,你要告訴它匹配它直到字符串的結尾。只是使用$

>>> p = re.compile(r'b*(abb*)*(a|)$') 
>>> print p.match('c') 
None 
>>> p.match('ababababab').group(0) 
'ababababab' 

PS-你可能已經注意到,我用r'pattern」而不是‘更上here(第一款)模式’