このコンテンツはまだ翻訳されていません。 翻訳に協力してください

キャプチャグループ

パターンの一部を丸括弧 (...)で囲むことができます。これは “キャプチャグループ” と呼ばれています。

これには2つの効果があります:

  1. String#match または RegExp#exec メソッドを利用したとき、マッチした部分を別々の配列アイテムに置くことができます。
  2. 丸括弧の後の量指定子を置いた場合、最後の文字ではなく全体に丸括弧が適用されます。

下の例では、パターン (go)+ は1つ以上の 'go' を見つけます:

alert( 'Gogogo now!'.match(/(go)+/i) ); // "Gogogo"

括弧なしだと、パターン /go+/g と、それに続けて1回以上の o の繰り返しを意味します、例えば、goooogooooooooo です。

括弧は単語 (go) をグループ化します。

もっと複雑なもの – メールアドレスにマッチする正規表現を作りましょう。

メールアドレスの例です:

my@mail.com
john.smith@site.com.uk

パターンは: [-.\w]+@([\w-]+\.)+[\w-]{2,20} です。

  • @ の前の最初のパートは、john.smith のように単語的な文字、ドットとダッシュを含みます [-.\w]+

  • 次は @ です。

  • そして、ドメインです。2階層のドメイン site.com かもしれないし、host.site.com.uk のようにサブドメインを持つ可能性があります。私たちは、mail. または site.com. のようなサブドメインに対して、“後ろにドットが続く単語” の1回以上の繰り返しをし、その後 .com.uk のような最後の部分に対する “単語” としてマッチさせることができます。

    “ドットが続く単語” は (\w+\.)+ (繰り返し) です。最後の言葉は末尾にドットは持たないので、単に \w{2,20} になります。量指定子 {2,20} は長さを制限します。.uk, .com.museum のようなドメインのゾーンは 20文字を超えることはできないためです。

    なので、ドメインパターンは (\w+\.)+\w{2,20} になります。さらに、ドメインはダッシュも許容するので \w[\w-] に置き換えます。これで最終的な結果を得ました。

この正規表現は完璧ではありませんが、たいていの場合動作します。これはパターンが短く、誤りや時折起きる間違いを修正するのには十分です。

例えば、ここでは文字列中のすべてのメールアドレスを見つけます:

let reg = /[-.\w]+@([\w-]+\.)+[\w-]{2,20}/g;

alert("my@mail.com @ his@site.com.uk".match(reg)); // my@mail.com,his@site.com.uk

括弧の内容

丸括弧は左から右へ番号付けされます。検索エンジンはそれぞれの中身を覚えており、パターンまたは置換文字列の中で内容を参照することができます。

例えば、(簡略化された) パターン <.*?> を使って HTML タグを見つけます。通常、結果の後に何かをしたいでしょう。

<...> の中身を丸括弧で囲むと、次のようにしてアクセスすることができます:

let str = '<h1>Hello, world!</h1>';
let reg = /<(.*?)>/;

alert( str.match(reg) ); // Array: ["<h1>", "h1"]

正規表現が /.../g フラグを持っていないときだけ、String#match の呼び出しはグループを返します。

グループとのすべてのマッチが必要な場合、RegExp と文字列のメソッド で説明したように RegExp#exec メソッドを使います。:

let str = '<h1>Hello, world!</h1>';

// 2つマッチします: 開始 <h1> と閉じ </h1> タグです
let reg = /<(.*?)>/g;

let match;

while (match = reg.exec(str)) {
  // 最初のマッチを表示: <h1>,h1
  // 次のマッチを表示: </h1>,/h1
  alert(match);
}

ここでは <(.*?)> で2つのマッチがあり、それぞれが完全なマッチとグループの配列です。

ネストされたグループ

括弧はネストすることができます。この場合も数字は左から右です。

例えば、<span class="my"> でタグを探すとき、次の内容に興味を持つかもしれません:

  1. タグ全体のコンテンツ: span class="my".
  2. タグの名前: span.
  3. タグの属性: class="my".

これらのための括弧を追加しましょう:

let str = '<span class="my">';

let reg = /<(([a-z]+)\s*([^>]*))>/;

let result = str.match(reg);
alert(result); // <span class="my">, span class="my", span, class="my"

グループは次のようになります:

result の先頭のインデックスは常に完全なマッチです。

次にグループで、左から右に番号付けされています。ここでは result[1] はタグコンテンツ全体が囲まれています。

次の result[2] は, 2つ目の開始 result[2] から対応する ) までのグループ – タグ名で、その後スペースはグループ化していませんが、result[3] で属性をグループ化しています。

もしグループが任意であり、マッチに存在しない場合、対応する result のインデックスは存在します(が、 undefined です)。

例えば、正規表現 a(z)?(c)? を考えてみましょう。これは "a" に任意の "z"が続き, それに任意の "c" が続くパターンを探します。

もし1文字 a に対して実行すると、結果はこのようになります:

let match = 'a'.match(/a(z)?(c)?/);

alert( match.length ); // 3
alert( match[0] ); // a (マッチ全体)
alert( match[1] ); // undefined
alert( match[2] ); // undefined

配列は長さ 3 ですが、すべてのグループは空です。

そして、文字列 ack の場合はより複雑なマッチになります:

let match = 'ack'.match(/a(z)?(c)?/)

alert( match.length ); // 3
alert( match[0] ); // ac (マッチ全体)
alert( match[1] ); // undefined, (z)? がないので。
alert( match[2] ); // c

配列の長さは不変で 3 です。しかしグループ (z)? は無いので、結果は ["ac", undefined, "c"] になります。

? を使用した非キャプチャグループ:

量指定子を正しく適用するために括弧が必要ですが、配列にそれらの内容が必要でない場合があります。

先頭に ?: を追加するとグループを除外することができます。

例えば、(go)+ を見つけたいですが、別の配列アイテムにその内容 (go) を覚えたくない場合、(?:go)+ と書くことができます。

下の例では、results の配列の別の要素として名前 “John” だけを取得します。:

let str = "Gogo John!";
// キャプチャから Gogo を除外します
let reg = /(?:go)+ (\w+)/i;

let result = str.match(reg);

alert( result.length ); // 2
alert( result[1] ); // John

タスク

形式 #abc または #abcdef で色をマッチする正規表現を書いてください。つまり、# の後に3桁または6桁の16進数が続きます。

使用例:

let reg = /your regexp/g;

let str = "color: #3f3; background-color: #AA00ef; and: #abcd";

alert( str.match(reg) ); // #3f3 #AA0ef

P.S. 正確に 3 または 6 桁の16進数であるべきです。#abcd のような値はマッチしません。

3桁の色 #abc を検索する正規表現は /#[a-f0-9]{3}/i です。

正確に3つの任意の16進数を指定できます。 私たちはそれ以上もそれ以下も必要ではありません。それを持っているか、持っていないかのどちらかです。

それらを追加する最も単純な方法は – 正規表現に追加することです: /#[a-f0-9]{3}([a-f0-9]{3})?/i

よりスマートな方法で書くこともできます: /#([a-f0-9]{3}){1,2}/i.

ここで正規表現 [a-f0-9]{3} は括弧の中にあり、全体として量指定子 {1,2} を適用します。

動作:

let reg = /#([a-f0-9]{3}){1,2}/gi;

let str = "color: #3f3; background-color: #AA00ef; and: #abcd";

alert( str.match(reg) ); // #3f3 #AA0ef #abc

ここで小さな問題があります: パターンは #abcd の中で #abc を見つけます。これを避けるには、末尾に \b を追加します。:

let reg = /#([a-f0-9]{3}){1,2}\b/gi;

let str = "color: #3f3; background-color: #AA00ef; and: #abcd";

alert( str.match(reg) ); // #3f3 #AA0ef

小数点のないものも含め正数を探す正規表現を作成してください。

使用した例:

let reg = /your regexp/g;

let str = "1.5 0 12. 123.4.";

alert( str.match(reg) );   // 1.5, 0, 12, 123.4

整数値は \d+.

小数点は: \.\d+.

小数点は任意なので、量指定子 '?' をもつ括弧の中に置きましょう。

これで完成です: \d+(\.\d+)?:

let reg = /\d+(\.\d+)?/g;

let str = "1.5 0 12. 123.4.";

alert( str.match(re) );   // 1.5, 0, 12, 123.4

整数、浮動小数点や負数も含むすべての10進数を探す正規表現を書いてください。

使用例:

let reg = /あなたの正規表現/g;

let str = "-1.5 0 2 -123.4.";

alert( str.match(re) ); // -1.5, 0, 2, -123.4

任意で少数部分をもつ正の数は(前のタスクより): \d+(\.\d+)?.

先頭に任意の - を追加しましょう。:

let reg = /-?\d+(\.\d+)?/g;

let str = "-1.5 0 2 -123.4.";

alert( str.match(reg) );   // -1.5, 0, 2, -123.4

算術式は2つの数字とそれらの間の演算子で構成されます。:

  • 1 + 2
  • 1.2 * 3.4
  • -3 / -6
  • -2 - 2

演算子は "+", "-", "*" または "/" のいずれかです。

先頭や末尾、間に余分なスペースがあるかもしれません。

式を取り、3つのアイテムを持つ配列を返す parse(expr) を作成してください。

  1. 最初の数値
  2. 演算子
  3. 2番目の数値

例:

let [a, op, b] = parse("1.2 * 3.4");

alert(a); // 1.2
alert(op); // *
alert(b); // 3.4

数値の正規表現は: -?\d+(\.\d+)? です。前のタスクで作ったものです。

演算子は、[-+*/] です。ダッシュ - を先頭に置きます。中央にある場合、ダッシュは文字の範囲を意味しますが、それは必要ないからです。

JavaScript の正規表現 /.../ の中ではスラッシュをエスケープする必要があることに注意してください。

私たちは、数値、演算子、そして別の数値が必要です。そしてそれらの間にスペースがある場合があります。

完全な正規表現は次のようになります: -?\d+(\.\d+)?\s*[-+*/]\s*-?\d+(\.\d+)?.

配列として結果を取得するため、必要なデータの周りに括弧を置きましょう: 数値と演算子です: (-?\d+(\.\d+)?)\s*([-+*/])\s*(-?\d+(\.\d+)?).

動作:

let reg = /(-?\d+(\.\d+)?)\s*([-+*\/])\s*(-?\d+(\.\d+)?)/;

alert( "1.2 + 12".match(reg) );

結果は次の内容を含みます:

  • result[0] == "1.2 + 12" (完全なマッチ)
  • result[1] == "1" (最初の括弧)
  • result[2] == "2" (2番目の括弧 – 小数部 (\.\d+)?)
  • result[3] == "+" (…)
  • result[4] == "12" (…)
  • result[5] == undefined (最後は小数部がないので undefined です)

必要なのは数値と演算子だけです。小数部だけは不要です。

なので、(?:\.\d+)? のように、?: を追加することで、キャプチャグループから余分なグループを取り除きましょう。

最終的な解法は次の通りです:

function parse(expr) {
  let reg = /(-?\d+(?:\.\d+)?)\s*([-+*\/])\s*(-?\d+(?:\.\d+)?)/;

  let result = expr.match(reg);

  if (!result) return;
  result.shift();

  return result;
}

alert( parse("-1.23 * 3.45") );  // -1.23, *, 3.45
チュートリアルマップ

コメント

コメントをする前に読んでください…
  • 自由に記事への追加や質問を投稿をしたり、それらに回答してください。
  • 数語のコードを挿入するには、<code> タグを使ってください。複数行の場合は <pre> を、10行を超える場合にはサンドボックスを使ってください(plnkr, JSBin, codepen…)。
  • 記事の中で理解できないことがあれば、詳しく説明してください。