違いは何ですか ?:、 ?!そして?=正規表現で?


106

私はこれらの表現の意味を検索しましたが、それらの正確な違いを理解できませんでした。これは彼らが言うことです:

  • ?: 表現に一致しますが、キャプチャしません。
  • ?= サフィックスに一致しますが、キャプチャから除外します。
  • ?! サフィックスがない場合に一致します。

私はこれらを単純なRegExで使用してみましたが、すべて同じような結果が得られました。例:次の3つの式は非常によく似た結果になります。

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*

テストケースをご提示ください。彼らは同じ結果を与えるべきではありません。
Bergi、

@ sepp2k、それはいくつかのケースで同じような結果ですが、そのうちの1つは質問で言及されました。
RKポダー

@Bergi、私は英語の単語、電話番号、URL、Eメール・アドレス、番号、など。含む、ランダムデータでそれをテスト
RK Poddar

4
@RKAgarwalああ、私はあなたがそこで何をしたかを見ます。*グループの後にを追加したので、それらは単に無視されます。
sepp2k

noobie note:これらは括弧の先頭でのみ使用し、括弧はキャプチャグループを形成します(異なる括弧セットはテキストの異なるセクションを抽出します)。
Ryan Taylor

回答:


150

?=とは、?!前者が一致するように指定された発現を必要とし、後者は、それを必要とすることではないと一致します。たとえばa(?=b)、「ab」の「a」には一致しますが、「ac」の「a」には一致しません。一方a(?!b)、「ac」の「a」には一致しますが、「ab」の「a」には一致しません。

?:とは?=つまり?=ながら除外全体の一致からの発現?:だけキャプチャグループを作成できません。したがって、たとえばa(?:b)、「abc」の「ab」と一致しますが、「abc」a(?=b)の「a」とのみ一致します。a(b)「ABC」の「AB」にマッチする「b」を含むキャプチャを作成します。


78
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

ここを確認してください:http : //www.regular-expressions.info/lookaround.html正規表現の先読みに関する非常に優れたチュートリアルと例があります。


15
しかし、JavaScriptは後読みを知りません。
Bergi、2012年

1
これは一般的な正規表現ではより完全です。
Yan Yang

/(?<= ^ a)b /はJavaScriptで私のために働いた!インターネット上のJavascriptを後ろから見るためのチュートリアルはないようです。
Y.吉井

最近のバージョンのブラウザーのみが、JSでの
Look Beakの

– anubhava純粋な正規表現を使用して/(?<= ^ a)b /に代わる方法を知りません。おそらく可能ですが、コールバック関数に依存する必要があります。
Y.吉井

21

よりよく理解するために、3つの式とキャプチャグループを適用して、各動作を分析してみましょう。

  • () キャプチャグループ -括弧内の正規表現を一致させる必要があります。一致するとキャプチャグループが作成されます
  • (?:) 非キャプチャグループ -括弧内の正規表現は一致する必要がありますが、キャプチャグループを作成しません
  • (?=) ポジティブな先読み -正規表現が一致しなければならないことを表明します
  • (?!) 否定的な先読み -正規表現に一致することが不可能であることを主張します

quitに適用q(u)iしましょう。qに一致し、キャプチャグループはuに一致します。キャプチャグループ内の一致が取得され、キャプチャグループが作成されます。したがって、エンジンは継続します。そして、一致します私を。この最後の試合は成功しました。quiが一致し、uを含むキャプチャグループが作成されます。quii

quitに適用q(?:u)iしましょう。この場合も、qに一致し、非キャプチャグループはuに一致します。非キャプチャグループからの一致が取得されますが、キャプチャグループは作成されません。したがって、エンジンは継続します。そして、一致します私を。この最後の試合は成功しました。quiが一致しましたquii

quitに適用q(?=u)iしましょう。先読みは肯定的で、その後に別のトークンが続きます。ここでも、一致したQと一致uと。この場合も、先読みの一致は破棄する必要があるため、エンジンは文字列からuに戻ります。先読みは成功したため、エンジンはに進みます。しかし、uと一致することはできません。したがって、このマッチの試みは失敗します。quiii

quitに適用q(?=u)uしましょう。先読みは肯定的で、その後に別のトークンが続きます。ここでも、一致したQと一致uと。先読みの一致は破棄する必要があるため、エンジンは文字列内からuに戻ります。先読みは成功したため、エンジンはに進みます。そしてuと一致します。したがって、このマッチの試みは成功しています。quが一致するquuuu

quitに適用q(?!i)uしましょう。この場合でも、先読みは正であり(一致しないため)、別のトークンが続きます。ここでも、一致したqとし、一致していませんuと。先読みの一致は破棄する必要があるため、エンジンは文字列内からuに戻ります。先読みは成功したため、エンジンはに進みます。そしてuと一致します。したがって、このマッチの試みは成功しています。quが一致するiqiuuu

つまり、結論として、先読みグループと非キャプチャグループの実際の違いは、存在をテストするか、一致をテストして保存するかだけです。捕獲グループは高価なので、慎重に使用してください。


> したがって、エンジンは文字列のiからuに戻ります。先読みは成功したため、エンジンはiを続行します。しかし、私はあなたと一致することができませんこれは完全に混乱しています。これが先読みの場合、なぜ後退するのですか?
緑の

1
@Green先読みやその他の先読み構成について理解する重要なことは、部分式が一致するかどうかを確認するために動作を実行しても、実際にはテキストを「消費」しないことです。少し混乱するかもしれません
freedev

7

foobarこれらと照合してみてください:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

最初の正規表現は一致し、最初のサブマッチとして「bar」を返します— (?=b)「b」に一致しますが、それを消費せず、次の括弧に残します。

2番目の正規表現は一致しません。これは、「foo」の後に「b」とは異なるものが続くことを期待しているためです。

(?:...)simpleとまったく同じ効果(...)がありますが、その部分はサブマッチとして返されません。


0

アサーションを理解する最も簡単な方法は、アサーションを正規表現に挿入されたコマンドとして扱うことです。エンジンがアサーションまで実行されると、アサーションによって記述された状態をすぐにチェックします。結果がtrueの場合、正規表現の実行を続けます。


0

これが本当の違いです:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

「?:」または「?=」の後のコンテンツを気にしない場合、「?:」と「?=」はまったく同じです。どちらも使用できます。

ただし、これらのコンテンツをさらに処理する必要がある場合(全体と一致するだけではありません。その場合は、単に "a(b)"を使用できます)代わりに "?="を使用する必要があります。原因「?:」はそれを通り抜けます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.