2016-06-18 133 views
4

假設我有一個字符串像這樣:Python的正則表達式:XOR運算

  1. "DT NN IN NN"
  2. "DT RB JJ NN"
  3. "DT JJ JJ NN"
  4. "DT RB RB NN NN"
  5. "DT RB RB"

所以,我有字符串列表:

list = ["DT NN IN NN", "DT RB JJ NN", "DT JJ JJ NN", "DT RB RB NN NN", "DT RB RB"] 

我有以下代碼:

pattern = "(?:DT\s+)+([?:RB\s+|?:JJ\s+])+(?:NN\s+)*NN$" 
for item in list: 
    m = re.match(pattern, item) 
    if m: 
     print item 

我從pattern要的是匹配與DT(出現一次或多次)啓動串要麼RBJJ(出現一次或多次),但不是兩次,然後以NN(再次出現一次或多次)結束。

因此,在最終結果中,我應該在屏幕上打印3和4。然而,用我的正則表達式,除此之外,我得到2,我不想要。如何更改pattern以便這可以工作?如何用XOR替換管道(OR)?

+1

那麼'NN'可以重複任意次數? –

+0

在這種情況下,不使用正則表達式會簡單得多。 –

+0

是的,'NN'可以重複多次,但必須以至少一個'NN'結尾。 – Belphegor

回答

2

的問題是如何定義的RBJJ存在。你沒有提到只有他們中的任何一個應該在場。這可以通過將它們與|(管道)分開並讓它們中的任一個重複一次或多次來實現(+)。試着改變你的模式是:

pattern = "(?:DT\s+)+(?:(RB\s+)+|(JJ\s+)+)(?:NN\s+)*NN$" 

此外,(?:<something>)被稱爲非捕獲組。你用它來說「我想要<something>被匹配,但是當我稍後選擇組的時候不包括在內,並且看起來它沒有使用任何組,你只是打印整個item(除非你掩蓋了爲簡潔的代碼),如果你真的不需要組,這裏是一個簡單的版本,會爲你工作:

pattern = "(DT\s+)+((RB\s+)+|(JJ\s+)+)(NN\s*)*NN$" 

我也讓白色空間的結尾組出現0次或更多次,而不是一個或更多次你喜歡你的原始圖案,隨時改變它

+0

謝謝,這個作品! – Belphegor

+0

@Belphegor np :) – th3an0maly

1

[...]字符類,你匹配一組包括?:+|,等字符。除了-來標記系列,字符類中沒有修飾符或特殊字符。

你必須要匹配的RB重複,或JJ

pattern = r"(?:DT\s+)+(?:(?:RB\s+)+|(?:JJ\s+)+)NN" 

我已經簡化下來;無論如何,你並沒有使用任何組。

這種模式的在線演示:https://regex101.com/r/iH4lE6/1

既然你不是靠捕獲組,所以沒有真正使用非捕獲組,無論是任何點;只需使用(...)而不是(?:...)來獲得較少的冗​​餘正則表達式。

您可能需要添加錨,以確保DT只在開頭匹配,並更換NN在與(NN\s+)*NN$年底末來錨定它,移動空格匹配到每個重複組的開始:

pattern = r"^DT(\s+DT)*((\s+RB)+|(\s+JJ)+)(\s+NN)+$" 

此版本的在線演示:https://regex101.com/r/iH4lE6/2

+0

根據[這個評論](http://stackoverflow.com/questions/37898679/python-regex-xor-operator/37898783#comment63250527_37898679)'NN'可以重複任意次數。 –

+0

這不適用於我,我得到一個像「DT JJ JJ NN JJ NN DT NN」匹配,我不需要這樣。它必須以DT開始,至少有一個(或多個)RB或JJ,然後以一個或多個NN結束。 – Belphegor

+0

@Belphegor:更新;你能否更新你的問題以包含該樣本? –

1

如果我正確地理解了這個問題,你可以通過首先將它分成兩個單獨的問題來解決這個問題:

  • DT開始,接着通過一個或多個RB秒,然後通過一個或多個NN S A的正則表達式:

    ^DT(\s+DT)*(\s+RB)+(\s+NN)+$ 
    
  • DT開頭的正則表達式,接着通過一個或多個JJ秒,然後一個或多個NN S:

    ^DT(\s+DT)*(\s+JJ)+(\s+NN)+$ 
    

現在,你可以簡單地把一管(或運營商)這兩者之間:

^((DT(\s+DT)*(\s+RB)+(\s+NN)+)|(DT(\s+DT)*(\s+JJ)+(\s+NN)+))$ 

,後來被其重構簡化它:

^DT(\s+DT)*((\s+RB)+|(\s+JJ)+)(\s+NN)+$ 

或使用可視化表示Regexper

visual representation of the regex

+0

感謝您的評論,這有一個例外:DT可以出現一次或多次(我剛纔看到我忘了在我原來的問題中提到)。我接受了另一個答案,因爲它在那裏工作+另一個人更快:) +1爲您的詳細答案,它絕對有幫助! – Belphegor