web-dev-qa-db-ja.com

非占領グループとは何ですか? (?:)は何をしますか?

どのように?:が使われていて、それは何のために良いのでしょうか?

1523

例を使ってこれを説明しよう。

次のテキストを見てください。

http://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex

今、私はそれの上に正規表現を適用すると...

(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

...次のようになります。

Match "http://stackoverflow.com/"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "https"
     Group 2: "stackoverflow.com"
     Group 3: "/questions/tagged/regex"

しかし、私はプロトコルについては気にしません - 私はただHostとURLのパスが欲しいのです。それで、私は正規表現を非キャプチャグループ(?:)を含むように変更します。

(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

今、私の結果はこのようになります:

Match "http://stackoverflow.com/"
     Group 1: "stackoverflow.com"
     Group 2: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "stackoverflow.com"
     Group 2: "/questions/tagged/regex"

見る?最初のグループは捕獲されていません。パーサーはそれをテキストのマッチングに使用しますが、最終結果では後で無視します。


編集:

要求に応じて、私もグループを説明しようとしましょう。

まあ、グループは多くの目的を果たします。それらはあなたがより大きなマッチ(これも名前を付けることができる)から正確な情報を抽出するのを手助けすることができます、彼らはあなたが以前にマッチしたグループを再マッチさせ、そして代用に使用できます。例をいくつか試してみましょう。

さて、あなたが何らかのXMLまたはHTMLを持っていると想像してみてください( regexは仕事に最適なツールではないかもしれない しかし、それは例としてNiceです)。あなたはタグを解析したいので、あなたはこのようなことをすることができます(分かりやすくするためにスペースを加えました):

   \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
   \<(.+?)\> [^<]*? \</\1\>

最初の正規表現は名前付きグループ(TAG)を持ち、2番目の正規表現は共通グループを使います。両方の正規表現は同じことをします:それらは最初のグループからの値(タグの名前)を使用して終了タグと一致します。違いは、最初のものは値を一致させるために名前を使用し、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/ をお勧めします。これには、正規表現のしくみについての詳細な説明がたくさんあります。それはまたから選ぶべき少数の正規表現エンジンを提供する。

1994
Ricardo Nolde

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

数字のテキストと一致させたいが、1、2、3、4、...のように書くことができるとします。数字の部分をキャプチャしたいが(オプションの)接尾辞は必要ない場合は、非キャプチャグループを使用できます。 。

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

これは、1、2、3 ...の形式、または1、2、3、...の形式の数値と一致しますが、数値部分のみを取り込みます。

143
Bill the Lizard

?:は、式をグループ化したいときに使用しますが、それをストリングの一致/キャプチャー部分として保存したくない場合は、.

例としては、IPアドレスと一致するものがあります。

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

私は最初の3オクテットを保存することを気にしないことに注意してください、しかし(?:...)グループ化はマッチをキャプチャして保存するオーバーヘッドを被ることなく正規表現を短くすることを可能にします。 

93
RC.

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

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

歴史的動機づけ:捕獲していないグループの存在は括弧を使って説明できる。式(a | b)cとa | bcを考えます。|よりも連結の優先順位が高いため、これらの式は2つの異なる言語(それぞれ{ac、bc}と{a、bc})を表します。ただし、括弧は、(他の回答で説明されているように)マッチンググループとしても使用されます。

括弧を付けたいが部分式をとらえたくない場合は、NON-CAPTURING GROUPSを使用します。例では、(?:a | b)c

16
user2369060

capture に一致するように正規表現内で後で使用できるグループ _または_ 正規表現の置換部分でそれらを使用できます。 キャプチャしない グループを作成すると、そのグループはこれらの理由のいずれかで使用されることから除外されます。 

あなたが多くの異なるものを捕獲しようとしていて、あなたが捕らえたくないいくつかのグループがあるならば、非捕獲グループは素晴らしいです。 

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

正規表現の中で後で使う例(後方参照):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [(nsサポートなしで)xmlタグを見つける]

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

後の正規表現の\1は最初のグループ(([A-Z][A-Z0-9]*)グループ)にあったのと同じテキストだけにマッチすることを意味します(この場合それは終了タグにマッチします)。

13
Bob Fincheimer

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

正規表現コード: - (?: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で、続きます。

しかし、?:を与えることで、マッチグループをキャプチャしないようにします(マッチしたグループではカウントオフされないので、グループ化番号は最初のキャプチャしたグループから始まり、キャプチャしないグループから始まります)。 -group(?:animal)は後でコードで呼び出すことはできません。

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

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

10
shekhar gehlot

私はJavaScriptの開発者であり、JavaScriptに関するその重要性を説明しようとしています。

Catとanimalを一致させたい場合に、両方の間にisを含める必要があるときにcat is animal と一致させるシナリオを考えてみましょう。

 // 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"]
6
Gaurav

複雑な正規表現では、多数のグループを使いたい場合があるかもしれません。そのうちのいくつかは繰り返しのマッチングのためのものであり、そのうちのいくつかは後方参照のためのものです。デフォルトでは、各グループに一致するテキストは後方参照配列にロードされます。たくさんのグループがあり、それらのうちのいくつかを後方参照配列から参照できるようにするだけでよい場合は、このデフォルトの振る舞いをオーバーライドして、特定のグループは繰り返し処理のためだけにあり、キャプチャーして保管する必要はない後方参照配列にあります。

5
Jack Peng

私が遭遇した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));

enter image description here

最初のグループ(?:([A-Za-z]+):)が非キャプチャグループであるなら、なぜ出力配列にhttp文字列を返すのかと思いました。

つまり、キャプチャしないグループの中に([A-Za-z]+)という入れ子のグループがあることに気付いたら。そのネストされたグループ([A-Za-z]+)は、それ自体では非キャプチャーグループ?:内のキャプチャーグループです(先頭に(?:([A-Za-z]+):)を持たない)。テキストhttpはまだキャプチャされますが、キャプチャしていないグループの内側でキャプチャしているグループの外側にあるコロンの:文字は、出力配列で報告されません。

4
RBT

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

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

では、住所のid部分だけが必要です。あなたがしたいのは、正規表現で()で囲まれたマッチ結果の最初のグループをつかむことです。これを行う方法は、非キャプチャグループ構文、すなわち?:を使用することです。そのため、正規表現(\p{Alpha}*[a-z])(?:@example.com)は電子メールのid部分のみを返します。

4
6pack kid

私はこれを言うためにトップの答えにコメントすることはできません。

キャプチャしないグループ(?...) は、元の完全一致からの任意の文字を削除しない _します(のみ)。 

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

4
Scott Anderson

マッチが成功したことを確認せずにキャプチャ変数を使用しないでください。

キャプチャ変数$ 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でブロントをキャプチャしないようにするために、(?:)が使用されます。以下のように:

Fred wants a burger

一致を保存したくない場合に便利です。

1
Harini

Google ChromeのdevToolsを開き、次に[コンソール]タブを開き、次のように入力します。

"Peace".match(/(\w)(\w)(\w)/)

それを実行してください、そしてあなたは見るでしょう:

["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]

JavaScript RegExpエンジンは3つのグループ、インデックス1、2、3を持つアイテムをキャプチャします。結果を見るために今度は非キャプチャマークを使用します。

"Peace".match(/(?:\w)(\w)(\w)/)

年です。結果:

["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]

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

0
AmerllicA

その日付は、2019年1月1日、2019年5月2日、または他の日付として言及されていて、単純にそれを dd/mm/yyyy 形式に変換したい場合そのため、1月や2月の月の名前は必要ありません。そのため、数字部分をキャプチャーするには(オプションの)接尾辞は必要ないので、キャプチャーしないグループを使用できます。

正規表現は次のようになります。

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

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

0
Naved Ahmad