正規表現の非キャプチャグループとは何ですか?


回答:


2328

例を挙げて説明します。

次のテキストを検討してください。

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/をお勧めします。これは、正規表現がどのように機能するかについてかなりの詳細を提供します。また、いくつかの正規表現エンジンから選択できます。


3
@ajsie:結果に対して置換操作を実行する場合は、従来の(キャプチャ)グループが最も役立ちます。これは、カンマで区切られた姓と名を取得
スティーブ

2
いいえ、同じではありません。
Ricardo Nolde 2013

4
正規表現を分割区切り文字として使用する場合、非キャプチャグループが非常に有用であることも指摘するかもしれません: "Alice and Bob" -split "\ s +(?: and | or)\ s +"
Yevgeniy

7
非キャプチャグループ(?:)と先読みと後読みのアサーション(?=、?!)の違いを説明すると興味深いでしょう。正規表現について学び始めたばかりですが、理解したことによると、非キャプチャグループは一致に使用され、一致するものを「返す」が、その「戻り値」は後方参照用に「格納」されていません。一方、先読みと後読みのアサーションは「保存」されるだけでなく、一致の一部でもありません。何かが一致することを表明するだけですが、「一致」の値は無視されます。 。(私はだいたい正しいですか?)
クリスチャン

5
[]はセットです。[123]セット内の任意の文字に1回一致します。[^ 123]は、セット内にないものに一度一致します。[^ / \ r \ n] +は、/、\ r、\ nとは異なる1つ以上の文字に一致します。
Ricardo Nolde 14年

180

キャプチャグループを使用して、式を整理および解析できます。非キャプチャグループには最初の利点がありますが、2番目のオーバーヘッドはありません。たとえば、非キャプチャグループはオプションであるとも言えます。

数値テキストと一致させたいが、一部の数値は1st、2nd、3rd、4thと書くことができるとします...数値部分をキャプチャしたいが(オプションの)サフィックスをキャプチャしたくない場合は、非キャプチャグループを使用できます。 。

([0-9]+)(?:st|nd|rd|th)?

これは、1、2、3 ...の形式、または1st、2nd、3rd ...の形式の数値に一致しますが、数値部分のみをキャプチャします。


3
簡潔で、おそらくここで最も良い説明。
NelsonGon

107

?: 式をグループ化したいが、文字列の一致/キャプチャされた部分として保存したくない場合に使用します。

例は、IPアドレスと一致するものです。

/(?:\d{1,3}\.){3}\d{1,3}/

最初の3オクテットを保存する必要はありませんが、(?:...)グループ化により、一致のキャプチャと保存のオーバーヘッドを発生させることなく、正規表現を短縮できます。


38

グループを非キャプチャーにします。つまり、そのグループに一致するサブストリングはキャプチャーのリストに含まれません。違いを説明するルビーの例:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]

ここで "abc" .match(/.(.)./)。capturesだけを使用できないのはなぜですか?
PRASANNA SARAF

@PRASANNASARAFもちろんできます。コードの要点は、それ(?:)がキャプチャを生成しないことを示すことであり、の有用な例を示すことではありませんでした(?:)(?:)サブ式をグループ化したい場合(たとえば、非アトミックなサブ式に数量詞を適用したい場合、またはのスコープを制限したい場合|)は便利ですが、何もキャプチャしたくありません。
sepp2k

26

歴史的動機:

非捕捉グループの存在は、括弧を使用して説明できます。

式考える(a|b)ca|bc上連結の優先度に起因し、|これらの式は、2つの異なる言語を表し、({ac, bc}及び{a, bc}それぞれ)。

ただし、括弧は一致グループとしても使用されます(他の回答で説明されているように...)。

かっこは入れたいがサブ式はキャプチャしない場合は、NON-CAPTURING GROUPSを使用します。例では、(?:a|b)c


6
なんでかしら。私は「なぜ」がこの情報を記憶するために不可欠であると思うので。
JMIマディソン2018

22

例でこれを試してみましょう:

正規表現コード: (?: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)後でコードで呼び出すことはできません。

これが非捕捉グループの使用を説明することを願っています。

ここに画像の説明を入力してください


14

グループのキャプチャあなたが一致する正規表現中に、後に使用することができますまたはあなたが正規表現の交換部品でそれらを使用することができます。非キャプチャグループを作成すると、これらの理由のいずれかでそのグループの使用が除外されます。

非キャプチャグループは、さまざまなものをキャプチャしようとしていて、キャプチャしたくないグループがある場合に最適です。

それが彼らが存在する理由のほとんどです。グループについて学習している間、原子グループについて学習しますが、それらは多くのことを行います!ルックアラウンドグループもありますが、少し複雑であまり使用されていません。

後で正規表現で使用する例(後方参照):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [xmlタグを検索します(nsサポートなし)]

([A-Z][A-Z0-9]*) キャプチャグループです(この場合はタグ名です)。

後の正規表現では\1、最初のグループ(([A-Z][A-Z0-9]*)グループ)にあったのと同じテキストのみに一致します(この場合は終了タグに一致しています)。


ORを照合するために後でどのように使用されるかについて簡単な例を挙げていただけますか?
never_had_a_name 2010

つまり、後で一致させるために使用したり、置換で使用したりできます。その文のまた
はは

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"]

7

複雑な正規表現では、多数のグループを使用したいという状況が発生する可能性があります。その一部は繰り返しマッチングに使用され、一部は後方参照を提供するために使用されます。デフォルトでは、各グループに一致するテキストが後方参照配列に読み込まれます。多数のグループがあり、後方参照配列からそれらの一部を参照するだけでよい場合は、このデフォルトの動作をオーバーライドして、特定のグループが繰り返し処理のためにのみ存在し、キャプチャして保存する必要がないことを正規表現に伝えることができます。後方参照配列内。


7

私はこれを言うために上位の回答にコメントすることはできません。上位の回答でのみ暗示される明示的なポイントを追加したいと思います。

非キャプチャグループ(?...) は、元の完全一致から文字を削除、プログラマに対して視覚的に正規表現を再編成するだけです。

無関係な文字を定義せずに正規表現の特定の部分にアクセスするには、常に使用する必要があります .group(<index>)


2
あなたは残りの回答に欠けていた最も重要なヒントを提供しました。私は望ましい結果が得られなかったので、それらの中のすべての例を試し、選択的な中傷を使用しました。あなたの投稿だけが私がどこが間違っているかを私に示しました。
Seshadri R 2018

それを聞いてうれしい!
スコットアンダーソン

6

tl; dr非キャプチャグループ名前が示すとおり、正規表現の一部であり、一致に含めたくない?:ため、グループを非キャプチャとして定義することができます。

メールアドレスを持っているとしましょうexample@example.com。次の正規表現は、id部分と@ example.com部分の2つのグループを作成します。(\p{Alpha}*[a-z])(@example.com)。簡単にするために、@文字を含むドメイン名全体を抽出しています。

ここで、アドレスのid部分だけが必要だとしましょう。あなたがしたいことは()、正規表現で囲まれた一致結果の最初のグループを取得することです。これを行う方法は、非キャプチャグループ構文、つまりを使用すること?:です。したがって、正規表現(\p{Alpha}*[a-z])(?:@example.com)はメールのid部分のみを返します。


5

私が遭遇した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はキャプチャされますが、:非キャプチャグループの内側でキャプチャグループの外側にあるコロン文字は、出力配列で報告されません。


2

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]

これは非捕獲グループとは何かが明らかです。


2

答えを出そうと思います。一致が成功したことを確認せずにキャプチャ変数を使用しないでください。

キャプチャ変数、$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

マッチを保存したくない場合に便利です。


1

非常に単純です。単純な日付の例で理解できます。日付が2019年1月1日、2019年5月2日、またはその他の日付として言及されていて、単にdd / mm / yyyyに変換したいとします。形式場合は、月のは必要ありません。つまり、1月または2月の名前なので、数値部分をキャプチャするために(オプションの)サフィックスをキャプチャするために、非キャプチャグループを使用できます。

正規表現は

([0-9]+)(?:January|February)?

それと同じくらい簡単です。

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