非キャプチャグループ、つまり(?:)
、正規表現でどのように使用され、どのような目的に適していますか?
非キャプチャグループ、つまり(?:)
、正規表現でどのように使用され、どのような目的に適していますか?
回答:
例を挙げて説明します。
次のテキストを検討してください。
http://stackoverflow.com/
/programming/tagged/regex
ここで、以下の正規表現を適用すると...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
...次の結果が得られます。
Match "http://stackoverflow.com/"
Group 1: "http"
Group 2: "stackoverflow.com"
Group 3: "/"
Match "/programming/tagged/regex"
Group 1: "https"
Group 2: "stackoverflow.com"
Group 3: "/questions/tagged/regex"
しかし、プロトコルについては気にしません。URLのホストとパスだけが必要です。そこで、私は非捕獲グループを含むように正規表現を変更します(?:)
。
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
今、私の結果は次のようになります:
Match "http://stackoverflow.com/"
Group 1: "stackoverflow.com"
Group 2: "/"
Match "/programming/tagged/regex"
Group 1: "stackoverflow.com"
Group 2: "/questions/tagged/regex"
見る?最初のグループは捕獲されていません。パーサーはこれを使用してテキストを照合しますが、最終結果では後で無視します。
ご要望に応じて、グループについても説明させてください。
まあ、グループは多くの目的を果たします。これらは、より大きな一致(名前も指定可能)から正確な情報を抽出するのに役立ち、以前に一致したグループを再一致させ、置換に使用できます。いくつかの例を試してみましょうか。
ある種のXMLまたはHTMLがあると想像してください(正規表現はその仕事に最適なツールではないかもしれませんが、例としてはすばらしいことです)。タグを解析したいので、次のようなことができます(理解しやすいようにスペースを追加しました)。
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
\<(.+?)\> [^<]*? \</\1\>
最初の正規表現には名前付きグループ(TAG)がありますが、2番目の正規表現は共通グループを使用します。どちらの正規表現も同じことを行います。最初のグループの値(タグの名前)を使用して、終了タグを照合します。違いは、1つ目は名前を使用して値を照合し、2つ目はグループインデックス(1から開始)を使用することです。
それでは、いくつかの置換を試してみましょう。次のテキストを検討してください。
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
ここで、このばかげた正規表現を使いましょう。
\b(\S)(\S)(\S)(\S*)\b
この正規表現は、3文字以上の単語を照合し、グループを使用して最初の3文字を区切ります。結果はこれです:
Match "Lorem"
Group 1: "L"
Group 2: "o"
Group 3: "r"
Group 4: "em"
Match "ipsum"
Group 1: "i"
Group 2: "p"
Group 3: "s"
Group 4: "um"
...
Match "consectetuer"
Group 1: "c"
Group 2: "o"
Group 3: "n"
Group 4: "sectetuer"
...
したがって、置換文字列を適用すると、次のようになります。
$1_$3$2_$4
...その上で、最初のグループを使用し、アンダースコアを追加し、3番目のグループを使用し、次に2番目のグループを使用し、別のアンダースコアを追加し、次に4番目のグループを追加します。結果の文字列は次のようになります。
L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.
名前付きグループを置換に使用することもできます${name}
。
正規表現をいじるには、http: //regex101.com/をお勧めします。これは、正規表現がどのように機能するかについてかなりの詳細を提供します。また、いくつかの正規表現エンジンから選択できます。
キャプチャグループを使用して、式を整理および解析できます。非キャプチャグループには最初の利点がありますが、2番目のオーバーヘッドはありません。たとえば、非キャプチャグループはオプションであるとも言えます。
数値テキストと一致させたいが、一部の数値は1st、2nd、3rd、4thと書くことができるとします...数値部分をキャプチャしたいが(オプションの)サフィックスをキャプチャしたくない場合は、非キャプチャグループを使用できます。 。
([0-9]+)(?:st|nd|rd|th)?
これは、1、2、3 ...の形式、または1st、2nd、3rd ...の形式の数値に一致しますが、数値部分のみをキャプチャします。
グループを非キャプチャーにします。つまり、そのグループに一致するサブストリングはキャプチャーのリストに含まれません。違いを説明するルビーの例:
"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
(?:)
がキャプチャを生成しないことを示すことであり、の有用な例を示すことではありませんでした(?:)
。(?:)
サブ式をグループ化したい場合(たとえば、非アトミックなサブ式に数量詞を適用したい場合、またはのスコープを制限したい場合|
)は便利ですが、何もキャプチャしたくありません。
歴史的動機:
非捕捉グループの存在は、括弧を使用して説明できます。
式考える(a|b)c
とa|bc
上連結の優先度に起因し、|
これらの式は、2つの異なる言語を表し、({ac, bc}
及び{a, bc}
それぞれ)。
ただし、括弧は一致グループとしても使用されます(他の回答で説明されているように...)。
かっこは入れたいがサブ式はキャプチャしない場合は、NON-CAPTURING GROUPSを使用します。例では、(?:a|b)c
例でこれを試してみましょう:
正規表現コード: (?:animal)(?:=)(\w+)(,)\1\2
検索文字列:
ライン1 - animal=cat,dog,cat,tiger,dog
2行目 - animal=cat,cat,dog,dog,tiger
行3- animal=dog,dog,cat,cat,tiger
(?:animal)
->キャプチャされていないグループ1
(?:=)
->キャプチャされていないグループ2
(\w+)
->キャプチャされたグループ1
(,)
->キャプチャされたグループ2
\1
->キャプチャされたグループ1の結果。つまり、ライン1は猫、ライン2は猫、ライン3は犬です。
\2
->キャプチャされたグループ2の結果、つまりコンマ(、)
したがって、このコードでは\1
、\2
私たちは、それぞれ、後にコードでのリコールまたはキャプチャグループ1及び2の結果を繰り返します。
コードの順序に従って、(?:animal)
グループ1および(?:=)
グループ2である必要があります。
しかし、?:
私たちに与えることにより、マッチグループをキャプチャしないようにします(マッチしたグループではカウントされないため、グループ化番号は最初のキャプチャされたグループから始まり、キャプチャされていないグループから始まります)。したがって、マッチグループの結果の繰り返し(?:animal)
後でコードで呼び出すことはできません。
これが非捕捉グループの使用を説明することを願っています。
グループのキャプチャあなたが一致する正規表現中に、後に使用することができますまたはあなたが正規表現の交換部品でそれらを使用することができます。非キャプチャグループを作成すると、これらの理由のいずれかでそのグループの使用が除外されます。
非キャプチャグループは、さまざまなものをキャプチャしようとしていて、キャプチャしたくないグループがある場合に最適です。
それが彼らが存在する理由のほとんどです。グループについて学習している間、原子グループについて学習しますが、それらは多くのことを行います!ルックアラウンドグループもありますが、少し複雑であまり使用されていません。
後で正規表現で使用する例(後方参照):
<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>
[xmlタグを検索します(nsサポートなし)]
([A-Z][A-Z0-9]*)
キャプチャグループです(この場合はタグ名です)。
後の正規表現では\1
、最初のグループ(([A-Z][A-Z0-9]*)
グループ)にあったのと同じテキストのみに一致します(この場合は終了タグに一致しています)。
さて、私はJavaScript開発者であり、JavaScriptに関連するその重要性を説明しようと思います。
cat is animal
猫と動物を一致させたい場合に一致させたいシナリオを考えてis
ください。
// this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]
// using lookahead pattern it will match only "cat" we can
// use lookahead but the problem is we can not give anything
// at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]
//so I gave another grouping parenthesis for animal
// in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]
// we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]
私はこれを言うために上位の回答にコメントすることはできません。上位の回答でのみ暗示される明示的なポイントを追加したいと思います。
非キャプチャグループ(?...)
は、元の完全一致から文字を削除せず、プログラマに対して視覚的に正規表現を再編成するだけです。
無関係な文字を定義せずに正規表現の特定の部分にアクセスするには、常に使用する必要があります .group(<index>)
tl; dr非キャプチャグループ。名前が示すとおり、正規表現の一部であり、一致に含めたくない?:
ため、グループを非キャプチャとして定義することができます。
メールアドレスを持っているとしましょうexample@example.com
。次の正規表現は、id部分と@ example.com部分の2つのグループを作成します。(\p{Alpha}*[a-z])(@example.com)
。簡単にするために、@
文字を含むドメイン名全体を抽出しています。
ここで、アドレスのid部分だけが必要だとしましょう。あなたがしたいことは()
、正規表現で囲まれた一致結果の最初のグループを取得することです。これを行う方法は、非キャプチャグループ構文、つまりを使用すること?:
です。したがって、正規表現(\p{Alpha}*[a-z])(?:@example.com)
はメールのid部分のみを返します。
私が遭遇した1つの興味深いことは、非キャプチャグループ内にキャプチャグループを持つことができるという事実です。一致するWeb URLについては、以下の正規表現をご覧ください。
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
入力URL文字列:
var url = "http://www.ora.com:80/goodparts?q#fragment";
私の正規表現の最初のグループは、(?:([A-Za-z]+):)
プロトコルスキームとコロン:
文字に一致する非キャプチャグループです。http:
ただし、コードの下で実行していると、返された配列の最初のインデックスに、コロンhttp
と考えていたときに文字列が含まれていることがhttp
わかりました。:
どちらも非捕獲グループ内にいるため、報告されません。
console.debug(parse_url_regex.exec(url));
最初のグループ(?:([A-Za-z]+):)
が非キャプチャグループである場合http
、出力配列に文字列を返す理由を考えました。
したがって([A-Za-z]+)
、非キャプチャグループ内にネストされたグループがあることに気づいた場合。そのネストされたグループ([A-Za-z]+)
は、?:
それ自体が非キャプチャグループ内のキャプチャグループ(最初は持たない)(?:([A-Za-z]+):)
です。そのため、テキストhttp
はキャプチャされますが、:
非キャプチャグループの内側でキャプチャグループの外側にあるコロン文字は、出力配列で報告されません。
Google Chrome devToolsを開き、[コンソール]タブを開き、次のように入力します。
"Peace".match(/(\w)(\w)(\w)/)
それを実行すると、次のようになります。
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
JavaScript
正規表現エンジンキャプチャ三つのグループ、インデックス1,2,3を持つアイテム。次に、非キャプチャーマークを使用して結果を確認します。
"Peace".match(/(?:\w)(\w)(\w)/)
結果は次のとおりです。
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]
これは非捕獲グループとは何かが明らかです。
答えを出そうと思います。一致が成功したことを確認せずにキャプチャ変数を使用しないでください。
キャプチャ変数、$1
などは、一致が成功しない限り無効であり、それらもクリアされません。
#!/usr/bin/perl
use warnings;
use strict;
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
print "Fred wants a $1";
}
else
{
print "Fred dont wants a $1 $2";
}
上記の例では、ブロントのキャプチャを回避するために$1
、(?:)
が使用されています。
パターンが一致した場合、$1
次のグループ化されたパターンとしてキャプチャされます。
したがって、出力は次のようになります。
Fred wants a burger
マッチを保存したくない場合に便利です。