15

特定の正規表現の文字列ですべての一致を見つける必要があります。findall()期待どおりに動作しないケースに遭遇するまで、私はそれを行ってきました。例えば:

regex = re.compile('(\d+,?)+')
s = 'There are 9,000,000 bicycles in Beijing.'

print re.search(regex, s).group(0)
> 9,000,000

print re.findall(regex, s)
> ['000']

この場合search()、必要なもの(最長の一致)を返しますが、findall()動作は異なりますが、ドキュメントは同じである必要があることを暗示しています。

findall()最初のパターンだけでなく、パターンのすべての出現に一致search()します。

  • 挙動が違うのはなぜ?

  • search()with findall() (または他の何か)の結果を得るにはどうすればよいですか?

4

2 に答える 2

19

わかりました、何が起こっているのかわかりました...ドキュメントから:

パターンに 1 つ以上のグループが存在する場合は、グループのリストを返します。パターンに複数のグループがある場合、これはタプルのリストになります。

結局のところ、"(\d+,?)" というグループがあります。つまり、返されるのは、このグループの最後のオカレンス、つまり 000 です。

1 つの解決策は、次のように正規表現全体をグループで囲むことです。

regex = re.compile('((\d+,?)+)')

次に、一致した両方のグループを含むタプルである [('9,000,000', '000')] を返します。もちろん、あなたは最初のものだけを気にします。

個人的には、次の正規表現を使用します

regex = re.compile('((\d+,)*\d+)')

「これは悪い数字 9,123 です」などの一致を避けるためです。

編集。

式を括弧で囲んだり、タプルを処理したりする必要がないようにする方法を次に示します。

s = "..."
regex = re.compile('(\d+,?)+')
it = re.finditer(regex, s)

for match in it:
  print match.group(0)

finditer は、見つかったすべての一致にアクセスするために使用できる反復子を返します。これらの一致オブジェクトは re.search が返すものと同じであるため、group(0) は期待どおりの結果を返します。

于 2011-11-13T07:13:01.803 に答える
7

@aleph_null の回答は、問題の原因を正しく説明していますが、より良い解決策があると思います。次の正規表現を使用します。

regex = re.compile(r'\d+(?:,\d+)*')

それが優れているいくつかの理由:

  1. (?:...)は非キャプチャ グループであるため、一致ごとに 1 つの結果しか得られません。

  2. \d+(?:,\d+)*より優れた正規表現であり、より効率的で、誤検知を返す可能性が低くなります。

  3. 可能であれば、正規表現には常に Python の生の文字列を使用する必要があります。正規表現のエスケープ シーケンス ( word border\bなど)が文字列リテラル エスケープ シーケンス ( backspaceなど)として解釈されることに驚かれることはあまりありません。\b

于 2011-11-13T08:11:28.987 に答える