2016-04-10 6 views
1

を含めた文字列と一致したときに、私のマッチングが正常に動作しないように思われる次のような場合があります。奇妙な正規表現の振る舞いドット

import re 

test_case1 = u"I will meet you at 2 pm" 
test_case2 = u"I will meet you at 2 p.m." 
test_case3 = u"I will meet you at 2 p.m. " 
test_case4 = u"I will meet you at 2 p.m. pm " 

list_of_words = ['p.m.', 'pm'] # list of words that can be enlarged 

# join all words into an or expression and escape all punctuation 
joined_words = '|'.join([re.escape(x) for x in list_of_words]) 
# create a regex that will match a word from the list of words only if it is 
# at the start/end of the sentence or it is between two word boundaries 
match_regex = r'(^|\b)('+joined_words+r')(\b|$)' 
comp_regex = re.compile(match_regex, re.IGNORECASE) # compile the final regex 

print comp_regex.findall(test_case1), len(comp_regex.findall(test_case1)) 
print comp_regex.findall(test_case2), len(comp_regex.findall(test_case2)) 
print comp_regex.findall(test_case3), len(comp_regex.findall(test_case3)) 
print comp_regex.findall(test_case4), len(comp_regex.findall(test_case4)) 

をI入手4のテストケースについて以下の結果:

[(u'', u'pm', u'')] 1 
[(u'', u'p.m.', u'')] 1 
[] 0 
[(u'', u'pm', u'')] 1 

1番目と2番目のケースは正常に動作しているようですが、3番目のケースは "pm"と一致しません。たとえ私が正規表現で "\ b"という単語境界を使っていても、後に空白があるとします。

第4のケースは、「p.m.」と一致していないようです。まったく "pm"にしか一致しません。

問題がどこにあるのか理解できないようです。何か助けに感謝します。

答えて

3

Python docs状態に関する\b

は、単語の先頭や末尾に限る、空の文字列にマッチします。単語は、の英数字またはアンダースコア文字のシーケンスとして定義されるため、単語の末尾は空白または英数字以外のアンダースコアで示されます。正式には、\ bは\ wと\ w文字の境界(またはその逆)、または\ wと文字列の開始/終了の間に定義されているため、英数字とみなされる文字の正確なセットはUNICODEフラグとLOCALEフラグの値について説明します。たとえば、r '\ bfoo \ b'は 'foo'、 'foo'、 '(foo)'、 'bar foo baz'に一致しますが、 'foobar'や 'foo3'には一致しません。文字の範囲内では、\ bはバックスペース文字を表し、Pythonの文字列リテラルとの互換性を保ちます。

その定義.によるので\bp.m.後に一致していない単語の終わりをマークすることはできません。あなたの試合に次のような変更を加えると、あなたは予想通りの行動を得るでしょう:

2

あなたは試みることができる:

を使用すると、最後の行でp.mと午後たい場合:あなたが最初に、午後をしたい場合example

または

match_regex = r'(^|\s)('+joined_words+r')(\s|$)' 

をのみ:example