web-dev-qa-db-ja.com

違いは何ですか 。*?および。*正規表現?

正規表現を使用して文字列を2つの部分に分割しようとしています。文字列の形式は次のとおりです。

text to extract<number>

私は(.*?)<<(.*?)>を使用してきましたが、正規表現を少し読んだ後、式に?が必要なのか疑問に思い始めました。私はこのサイトでそれらを見つけた後にそのようにしただけなので、違いが何であるか正確にはわかりません。

117
Doug

貪欲な量指定子とそうでない量指定子の違いです。

入力101000000000100を考慮してください。

1.*1を使用すると、*は貪欲です-最後まで一致し、1と一致するまでバックトラックし、1010000000001が残ります。
.*?は貪欲ではありません。 *は何にも一致しませんが、1に一致するまで余分な文字の一致を試み、最終的に101に一致します。

すべての量指定子には、.*?.+?.{2,6}?、さらには.??という貪欲でないモードがあります。

あなたの場合、同様のパターンは<([^>]*)>である可能性があります-大なり記号以外のすべてに一致します(厳密には、><>)。

Quantifier Cheat Sheet を参照してください。

141
Kobi

欲張りと非欲張り

デフォルトでの正規表現の繰り返しはgreedy:彼らはできるだけ多くの担当者と一致しようとしますが、これが機能せずバックトラックする必要がある場合、パターン全体の一致が見つかるまで、一度に1人少ない担当者に一致するようにしてください。その結果、一致が最終的に発生すると、貪欲な繰り返しはmany担当者として可能な限り一致します。

繰り返し数量詞としての?は、この動作をnon-greedyに変更します。これはreluctantJavaの場合など )(および「レイジー」の場合もあります)。対照的に、この繰り返しは最初にfew担当者として一致しようとします。これが機能せず、バックトラックする必要がある場合、一致を開始しますもう1回繰り返します。その結果、一致が最終的に発生すると、消極的な繰り返しはfew担当者として可能な限り一致します。

参照資料


例1:AからZ

これら2つのパターンを比較してみましょう:A.*ZA.*?Z

次の入力が与えられた場合:

eeeAiiZuuuuAoooZeeee

パターンは次の一致を生成します。

まず、A.*Zが何をするかに注目しましょう。最初のAに一致すると、貪欲である.*は、最初にできるだけ多くの.に一致しようとします。

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

Zは一致しないため、エンジンはバックトラックし、.*は1つ少ない.と一致する必要があります。

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

これはさらに数回発生しますが、最終的にはこれに到達します。

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

Zが一致するようになったため、パターン全体が一致します。

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

対照的に、A.*?Zの消極的な繰り返しは最初にできるだけ少ない.に一致し、次に必要に応じて.をさらに取得します。これは、入力で2つの一致を見つける理由を説明しています。

以下は、2つのパターンが一致したものの視覚的表現です。

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

例:別の方法

多くのアプリケーションでは、上記の入力での2つの一致が望ましいため、欲張りな.*?の代わりに消極的な.*を使用して、オーバーマッチングを防ぎます。ただし、この特定のパターンには、否定文字クラスを使用するより適切な代替手段があります。

パターンA[^Z]*Zも、上記の入力のA.*?Zパターンと同じ2つの一致を検出します( ideone.comで見られるように )。 [^Z]は、否定文字クラスと呼ばれるものです。Z以外のものに一致します。

2つのパターンの主な違いはパフォーマンスにあります。より厳密に言えば、否定された文字クラスは、指定された入力に対して一方向にしか一致しません。このパターンに貪欲な修飾子を使用するか、消極的な修飾子を使用するかは関係ありません。実際、いくつかのフレーバーでは、さらに改善し、所有量指定子と呼ばれるものを使用できますが、これはまったく逆戻りしません。

参照資料


例2:AからZZまで

この例は実例となるはずです。同じ入力に対して貪欲、嫌がり、否定の文字クラスパターンがどのように一致するかを示しています。

eeAiiZooAuuZZeeeZZfff

これらは上記の入力と一致します。

以下は、一致したものを視覚的に表したものです。

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

関連トピック

これらは、スタックオーバーフローに関する質問と回答へのリンクであり、興味深いトピックがいくつか含まれています。

1つの貪欲な繰り返しはoutgreedできます

150

あなたが持っているとしましょう:

<a></a>

<(.*)>a></aと一致しますが、<(.*?)>aと一致します。後者は、>の最初の一致後に停止します。 .*の1つまたは0の一致と、それに続く次の式をチェックします。

最初の>に一致する場合、最初の式<(.*)>は停止しません。 >の最後の一致まで続きます。

16
Simon