7

編集:補助的な回答を引き起こしたため、元の例を削除してください。タイトルも修正。

問題は、正規表現に「$」が存在すると、式の貪欲さに影響する理由です。

より簡単な例を次に示します。

>>> import re
>>> str = "baaaaaaaa"
>>> m = re.search(r"a+$", str)
>>> m.group()
'aaaaaaaa'
>>> m = re.search(r"a+?$", str)
>>> m.group()
'aaaaaaaa'

「?」何もしていないようです。ただし、「$」が削除されると、「?」が削除されることに注意してください。尊重されます:

>>> m = re.search(r"a+?", str)
>>> m.group()
'a'

編集: 言い換えれば、「a+?$」は最後の a だけでなく、すべての a に一致します。これは私が期待したものではありません。正規表現「+?」の説明は次のとおりです。python docsから:「追加 '?' 修飾子が非貪欲または最小限の方法で一致を実行するようにした後、可能な限り少ない文字が一致します。」

これは、この例では当てはまらないようです: 文字列 "a" は正規表現 "a+?$" と一致するため、文字列 "baaaaaaa" の同じ正規表現の一致が単一の a (右端の1)?

4

6 に答える 6

4

一致は「左端、次に最長」の順に「順序付け」されます。ただし、「最長」とは、貪欲でないことが許可される前に使用されていた用語であり、代わりに「各原子の推奨される繰り返し回数」のようなものを意味します。繰り返し回数よりも左端であることが重要です。したがって、「a +?$」は「baaaaa」の最後のAとは一致しません。これは、最初のAでの一致が文字列の早い段階で開始されるためです。

(コメントでOPを明確にした後、回答が変更されました。前のテキストについては履歴を参照してください。)

于 2011-05-04T00:37:03.947 に答える
4

欲張りでない修飾子は、一致が停止する場所にのみ影響し、開始する場所には影響しません。できるだけ遅く試合を開始したい場合.+?は、パターンの先頭に追加する必要があります。

がないと、文字列の末尾に一致する必要がないため、$パターンの貪欲さが減り、すぐに停止することができます。

編集:

詳細...この場合:

re.search(r"a+?$", "baaaaaaaa")

正規表現エンジンは、最初の「a」までのすべてを無視します。これがその仕組みだからですre.search。これは最初のに一致しa、一致を返す必要があります。ただし、の一致に到達する必要があるため、パターンにはまだ一致していません$。したがって、一度に1つずつ食べ続け、aをチェックし続け$ます。貪欲だった場合は、$それぞれの後をチェックしませんaが、それ以上一致できなくなった後でのみチェックしaます。

しかし、この場合:

re.search(r"a+?", "baaaaaaaa")

正規表現エンジンは、最初の一致を食べた後に完全に一致するかどうかをチェックし(貪欲ではないため) 、この場合は一致しないため成功します。$

于 2011-05-04T00:50:18.330 に答える
4

$正規表現に が存在しても、式の欲張り度には影響しません。マッチ全体が成功するために満たさなければならない別の条件を追加するだけです。

a+との両方が、最初に見つけたa+?ものを消費する必要があります。その後にさらに'sが続くa場合、は先に進み、それらも消費しますが、一方は 1 つだけで満足します。正規表現にもっと何かがあれば、より少ない's で解決することを厭わないでしょう。aaa+a+?a+aa+?

a+$と を使用するとa+?$、別の条件が追加されます。少なくとも 1 つに一致し、その後に文字列の末尾が a 続きます。a+それでも最初はすべての を消費しa、その後アンカー ( ) に渡し$ます。これは最初の試行で成功するためa+、その を返す必要はありませんa

一方、はに渡す前に、a+?最初は 1 つだけを消費します。これは失敗するため、制御は に戻され、別の制御が消費されて再びハンドオフされます。そして、最後のものを消費し、最終的に成功するまで、それは続きます。そうです、は と同じ数の に一致しますが、貪欲ではなく、しぶしぶそうします。a$a+?aa+?a$a+?$aa+$

他の場所で言及された左端が最も長いルールに関しては、Python のような Perl 由来の正規表現フレーバーには適用されませんでした。気が進まない量指定子がなくても、順序付けられた代替のおかげで、常に最大以下の一致を返すことができました。Jan の考えは正しかったと思います。Perl 由来の (または正規表現指向の) フレーバーは、貪欲ではなく、 eagerと呼ばれるべきです。

一番左が長いルールは、内部で NFA エンジンを使用する POSIX NFA 正規表現にのみ適用されると思いますが、DFA (テキスト指向) 正規表現と同じ結果を返す必要があります。

于 2011-05-05T22:39:37.083 に答える
1

元の質問への回答:

最初の search() が最短の一致ではなく、複数の「/」にまたがるのはなぜですか?

貪欲でないサブパターンは、パターン全体が成功するのと一致する最短の一致を取ります。あなたの例では、最後のサブパターンは$であるため、前のものは文字列の最後まで伸ばす必要があります。

修正された質問への回答:

貪欲でないサブパターンは、パターン全体が成功するのと一致する最短の一致を取ります。

別の見方をすると、貪欲でないサブパターンは、最初は可能な限り短い一致に一致します。ただし、これによりパターン全体が失敗する場合は、追加の文字で再試行されます。このプロセスは、サブパターンが失敗する (パターン全体が失敗する) か、パターン全体が一致するまで続きます。

于 2011-05-04T00:29:42.073 に答える
1

ここでは、2 つの問題が進行中です。グループを指定せずにgroup()を使用しましたが、明示的に括弧で囲まれたグループを使用した場合と括弧で囲まれたグループを使用しない場合の正規表現の動作の間で混乱していることがわかります。観察している括弧のないこの動作は、Python が提供する単なるショートカットであり、完全に理解するにはgroup()に関するドキュメントを読む必要があります。

>>> import re
>>> string = "baaa"
>>> 
>>> # Here you're searching for one or more `a`s until the end of the line.
>>> pattern = re.search(r"a+$", string)
>>> pattern.group()
'aaa'
>>> 
>>> # This means the same thing as above, since the presence of the `$`
>>> # cancels out any meaning that the `?` might have.
>>> pattern = re.search(r"a+?$", string)
>>> pattern.group()
'aaa'
>>> 
>>> # Here you remove the `$`, so it matches the least amount of `a` it can.
>>> pattern = re.search(r"a+?", string)
>>> pattern.group()
'a'

要点は、文字列が1 つのピリオドにa+?一致することです。aただし、は行末までa+?$一致しaます。明示的なグループ化がなければ、 をまったく意味を持たせるのに苦労することに注意してください。とにかく、一般的には、何をグループ化するのかを括弧で明示する方がよいでしょう。明示的なグループの例挙げましょう。?

>>> # This is close to the example pattern with `a+?$` and therefore `a+$`.
>>> # It matches `a`s until the end of the line. Again the `?` can't do anything.
>>> pattern = re.search(r"(a+?)$", string)
>>> pattern.group(1)
'aaa'
>>>
>>> # In order to get the `?` to work, you need something else in your pattern
>>> # and outside your group that can be matched that will allow the selection
>>> # of `a`s to be lazy. # In this case, the `.*` is greedy and will gobble up
>>> # everything that the lazy `a+?` doesn't want to.
>>> pattern = re.search(r"(a+?).*$", string)
>>> pattern.group(1)
'a'

編集:質問の古いバージョンに関連するテキストを削除しました。

于 2011-05-03T23:46:34.423 に答える
0

質問に重要な情報が含まれていない限り、このタスクに正規表現は不要であり、使用すべきではありません。

>>> import os
>>> p = "/we/shant/see/this/butshouldseethis"
>>> os.path.basename(p)
butshouldseethis
于 2011-05-03T23:49:04.240 に答える