正規表現を使用して文字列を2つの部分に分割しようとしています。文字列の形式は次のとおりです。
text to extract<number>
私はこれまで使用(.*?)<
してきましたが、<(.*?)>
これは問題なく機能しますが、正規表現を少し読んだ後?
、式になぜが必要なのか疑問に思い始めました。私はこのサイトでそれらを見つけた後でそのようにしただけなので、違いが何であるか正確にはわかりません。
正規表現を使用して文字列を2つの部分に分割しようとしています。文字列の形式は次のとおりです。
text to extract<number>
私はこれまで使用(.*?)<
してきましたが、<(.*?)>
これは問題なく機能しますが、正規表現を少し読んだ後?
、式になぜが必要なのか疑問に思い始めました。私はこのサイトでそれらを見つけた後でそのようにしただけなので、違いが何であるか正確にはわかりません。
正規表現での繰り返しはデフォルトで貪欲です。可能な限り多くの担当者に一致させようとします。これが機能せず、バックトラックする必要がある場合は、パターン全体が一致するまで、一度に1つ少ない担当者に一致させようとします。見つかった。その結果、最終的に一致が発生した場合、貪欲な繰り返しは可能な限り多くの担当者と一致します。
?
as繰り返し数量詞は、この振る舞いを貪欲ではないものに変更します。これは、 (Javaなどで)不本意とも呼ばれます(場合によっては「怠惰」)。対照的に、この繰り返しは最初にできるだけ少ない担当者に一致しようとします。これが機能せず、バックトラックする必要がある場合は、一度にもう1つの担当者に一致し始めます。その結果、最終的に一致が発生した場合、気が進まない繰り返しは可能な限り少ない担当者に一致します。
これらの2つのパターンを比較してみましょう:A.*Z
とA.*?Z
。
次の入力が与えられます:
eeeAiiZuuuuAoooZeeee
パターンは次の一致をもたらします。
A.*Z
1つの一致が得られます: AiiZuuuuAoooZ
( rubular.comを参照)A.*?Z
2つの一致が得られます:AiiZ
およびAoooZ
(rubular.comを参照)まず、何をするかに焦点を当てましょう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
のパターンと同じ2つの一致も検出します( ideone.comで確認できます)。は、いわゆる否定文字クラスです。これは、以外のものと一致します。A.*?Z
[^Z]
Z
2つのパターンの主な違いは、パフォーマンスにあります。より厳密であるため、否定された文字クラスは、特定の入力に対して一方向にしか一致しません。このパターンに貪欲な修飾子を使用するか、消極的な修飾子を使用するかは関係ありません。実際、一部のフレーバーでは、さらに優れた方法で、所有格数量詞と呼ばれるものを使用できます。これは、まったく後戻りしません。
この例は説明のためのものである必要があります。これは、同じ入力が与えられた場合に、貪欲で、消極的で、否定された文字クラスのパターンがどのように異なって一致するかを示しています。
eeAiiZooAuuZZeeeZZfff
上記の入力に一致するものは次のとおりです。
A[^Z]*ZZ
1つの一致が得られます: AuuZZ
( ideone.comで見られるように)A.*?ZZ
1つの一致が得られます: AiiZooAuuZZ
( ideone.comで見られるように)A.*ZZ
1つの一致が得られます: AiiZooAuuZZeeeZZ
( ideone.comで見られるように)それらが一致したものを視覚的に表現したものは次のとおりです。
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
これらは、興味があるかもしれないいくつかのトピックをカバーするstackoverflowに関する質問と回答へのリンクです。
これは、欲張りと非欲張りの数量詞の違いです。
入力について考えてみましょう101000000000100
。
を使用する1.*1
と、*
貪欲になります。最後まで一致し、一致するまでバックトラックして1
、を残します1010000000001
。
.*?
欲張りではありません。*
何にも一致しませんが、一致するまで余分な文字を一致させようとし1
、最終的にはに一致し101
ます。
すべての数量詞には、欲張りでないモードがあります:、、、、.*?
さらには。.+?
.{2,6}?
.??
あなたの場合、同様のパターンは-大なり記号以外のものに一致する可能性があります(厳密に言えば、との間<([^>]*)>
以外の0個以上の文字に一致します)。>
<
>
QuantifierCheatSheetを参照してください。
あなたが持っているとしましょう:
<a></a>
<(.*)>
一致a></a
する場所に<(.*?)>
一致しa
ます。後者は、の最初の一致後に停止し>
ます。.*
次の式が続く1つまたは0つの一致をチェックします。
最初の式は、最初の式<(.*)>
と一致しても停止しません>
。の最後の一致まで続き>
ます。