web-dev-qa-db-ja.com

JavaScriptの正規表現で一致したグループにどのようにアクセスしますか?

正規表現 を使用して文字列の一部を照合してから、その括弧で囲まれた部分文字列にアクセスします。

var myString = "something format_abc"; // I want "abc"

var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);

console.log(arr);     // Prints: [" format_abc", "abc"] .. so far so good.
console.log(arr[1]);  // Prints: undefined  (???)
console.log(arr[0]);  // Prints: format_undefined (!!!)

何がおかしいのですか?


私は上記の正規表現コードに問題がないことを発見しました:私がテストしていた実際の文字列はこれでした:

"date format_%A"

"%A"が未定義であると報告するのは非常に奇妙な振る舞いに思えますが、それはこの質問に直接関係しないので、私は新しいものをオープンしました、JavaScriptでマッチした部分文字列が "undefined"を返すのはなぜですか?


問題はconsole.logprintfステートメントのようにパラメータを取り、そして私がログに記録していた文字列("%A")が特別な値を持っていたので、それは次のパラメータの値を見つけようとしていました。

1180
nickf

このようなキャプチャグループにアクセスできます。

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc

そして複数の一致がある場合は、それらを繰り返すことができます。

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
match = myRegexp.exec(myString);
while (match != null) {
  // matched text: match[0]
  // match start: match.index
  // capturing group n: match[n]
  console.log(match[0])
  match = myRegexp.exec(myString);
}

1437
CMS

これは、マッチごとに n 番目のキャプチャグループを取得するために使用できる方法です。

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.Push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);

165
Mathias Bynens

var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);

\bはまったく同じものではありません。 (これは--format_foo/では動作しますが、format_a_bでは動作しません)しかし、私はあなたの表現に代わるものを見せたかったのです。もちろん、match呼び出しは重要なことです。

51
PhiLho

上記の複数一致の括弧の例に関して、私が欲しいものを手に入れなかった後、私はここで答えを探していました:

var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);

上記のwhileと.Push()でやや複雑な関数呼び出しを見た後、代わりにmystring.replace()で問題を非常にエレガントに解決できることがわかりました(置き換えは重要ではなく、実行もされません2番目のパラメータに対するCLEANの組み込み再帰関数呼び出しオプションは、次のとおりです。

var yourstring = 'something format_abc something format_def something format_ghi';

var matches = [];
yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.Push(p1); } );

この後、私は二度とほとんど何もしないために.match()を使うつもりはないと思います。

25
Alexz

あなたの文法はおそらく保つのが最善ではないでしょう。 FF/Geckoは、RegExpをFunctionの拡張として定義しています。
(FF2はtypeof(/pattern/) == 'function'まで行きました)

これはFFに固有のもののようです - IE、Opera、そしてChromeはすべて例外を投げます。

代わりに、RegExp#execまたはString#matchのいずれかの方法を使用してください。
同じ結果が得られます。

var regex = /(?:^|\s)format_(.*?)(?:\s|$)/;
var input = "something format_abc";

regex(input);        //=> [" format_abc", "abc"]
regex.exec(input);   //=> [" format_abc", "abc"]
input.match(regex);  //=> [" format_abc", "abc"]
16

大事なことを言い忘れたが、私は私のためにうまく働いた1行のコードを見つけた(JS ES6):

let reg = /#([\S]+)/igm; // Get hashtags.
let string = 'mi alegría es total! ✌????\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';

let matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);

これは戻ります:

['fiestasdefindeaño', 'PadreHijo', 'buenosmomentos', 'france', 'paris']
15
Sebastien H.

この答えで使われている用語:

  • Match は、以下のように文字列に対してRegExパターンを実行した結果を示します。someString.match(regexPattern)
  • 一致パターン は、入力文字列のすべての一致部分を示し、これらはすべて match 配列内にあります。これらはすべて入力文字列内のパターンのインスタンスです。
  • 一致したグループ RegExパターンで定義された、キャッチするすべてのグループを示します。 (括弧内のパターンは、/format_(.*?)/g、ここで(.*?)は一致グループです。)これらは 一致パターン の中にあります。

説明

マッチしたグループにアクセスするには、それぞれのマッチしたパターンに、マッチを反復する関数など)が必要です。これを実行する方法はいくつかあります。他の回答の多くが示すように、他のほとんどの回答ではwhileループを使用してすべてのマッチしたパターンを繰り返します)が、このアプローチの潜在的な危険性は知っています。代わりにnew RegExp()と照合する必要があります。これは、.exec()メソッドがジェネレータ関数 - )のように振る舞うためです。これはmatch があるたびに停止しますが、.lastIndexはそのまま続けます。次の.exec()呼び出しにあります。

コード例

以下は、すべてのマッチしたパターン、それぞれの_ searchStringname__がすべてのマッチしたグループを含む)の_ Arrayname__である)のmatchname__を返す関数Arrayname__の例です。単純なforname __-ループを使用したArray.prototype.map()関数と、より高性能な方法の両方。

簡潔なバージョン(コードが少なく、構文糖が多い)

これらは基本的に高速のforEachname __-ループではなくforname __-ループを実装するため、これらのパフォーマンスは低下します。

// Concise ES6/ES2015 syntax
const searchString = 
    (string, pattern) => 
        string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match => 
            new RegExp(pattern.source, pattern.flags)
            .exec(match));

// Or if you will, with ES5 syntax
function searchString(string, pattern) {
    return string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match =>
            new RegExp(pattern.source, pattern.flags)
            .exec(match));
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

パフォーマンスバージョン(より多くのコード、より少ない構文糖)

// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
    let result = [];

    const matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (let i = 0; i < matches.length; i++) {
        result.Push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
};

// Same thing, but with ES5 syntax
function searchString(string, pattern) {
    var result = [];

    var matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (var i = 0; i < matches.length; i++) {
        result.Push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

これらの代替案を他の回答で前述したものと比較することはまだしていませんが、このアプローチが他のものよりもパフォーマンスが低く、フェイルセーフが低いとは思えません。

12
Daniel Hallgren

execメソッドを呼び出す必要はありません。文字列に対して直接 "match"メソッドを使うことができます。括弧を忘れないでください。

var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...

位置0には、すべての結果を含むストリングがあります。位置1は最初の一致を括弧で表し、位置2は2番目の一致を括弧で分離したものです。入れ子の括弧は扱いにくいので注意してください。

11
Andre Carneiro

一対の括弧がある場合にのみ実用的なワンライナー。

while ( ( match = myRegex.exec( myStr ) ) && matches.Push( match[1] ) ) {};
7
Nabil Kadimi

あなたのコードを使う:

console.log(arr[1]);  // prints: abc
console.log(arr[0]);  // prints:  format_abc

編集:それが重要ならばSafari 3。

6
eyelidlessness

String#matchAllStage 3 Draft/2018年12月7日の提案 を参照)、マッチオブジェクト内のすべてのグループへのアクセスを単純化します(Group 0が完全マッチであることに注意) groupsはパターン内のキャプチャグループに対応します。

matchAllが利用可能であれば、whileループや/g..でexecを回避することができます。代わりに、matchAllを使用すると、より便利な for...ofarray spread 、または Array.from() コンストラクト

このメソッドは、C#のRegex.Matches、Pythonのre.finditer、PHPのpreg_match_allと同様の出力を生成します。

JSデモ(Google Chrome 73.0.3683.67(公式ビルド)、ベータ版(64ビット)でテスト済み)を参照してください。

var myString = "key1:value1, [email protected]=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values

console.log([...matches])ショー

enter image description here

また、マッチ値または特定のグループ値を取得することもできます。

let matchData = "key1:value1, [email protected]=value3".matchAll(/(\w+)[:=-](\w+)/g)
var matches = [...matchData]; // Note matchAll result is not re-iterable

console.log(Array.from(matches, m => m[0])); // All match (Group 0) values
// => [ "key1:value1", "key2-value2", "key3=value3" ]
console.log(Array.from(matches, m => m[1])); // All match (Group 1) values
// => [ "key1", "key2", "key3" ]

_ note _ ブラウザの互換性 の詳細を参照してください。

5

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.Push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'Rs.200 is Debited to A/c ...2031 on 02-12-14 20:05:49 (Clear Bal Rs.66248.77) AT ATM. TollFree 1800223344 18001024455 (6am-10pm)';
var myRegEx = /clear bal.+?(\d+\.?\d{2})/gi;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.Push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);

5
Jack

PhiLo に同意しても、あなたのコードは私には有効です(MacではFF3)。

/\bformat_(.*?)\b/

(しかし、もちろん、正規表現の文脈がわからないので、よくわかりません。)

2
PEZ

複数の一致を解析するために明示的なループは実際に必要ありません— String.prototype.replace(regex, func) で説明されているように、2番目の引数として置換関数を渡します。

var str = "Our chief weapon is {1}, {0} and {2}!"; 
var params= ['surprise', 'fear', 'ruthless efficiency'];
var patt = /{([^}]+)}/g;

str=str.replace(patt, function(m0, m1, position){return params[parseInt(m1)];});

document.write(str);

m0引数は、完全に一致した部分文字列{0}{1}などを表します。m1は、最初に一致したグループ、つまり0最初の一致。 positionは、一致するグループが見つかった文字列内の開始インデックスです。この場合は未使用です。

2
ccpizza
/*Regex function for extracting object from "window.location.search" string.
 */

var search = "?a=3&b=4&c=7"; // Example search string

var getSearchObj = function (searchString) {

    var match, key, value, obj = {};
    var pattern = /(\w+)=(\w+)/g;
    var search = searchString.substr(1); // Remove '?'

    while (match = pattern.exec(search)) {
        obj[match[0].split('=')[0]] = match[0].split('=')[1];
    }

    return obj;

};

console.log(getSearchObj(search));
1
Pawel Kwiecien

バックスラッシュとそれに続く一致グループの番号を使用して、正規表現で一致グループにアクセスできます。

/([a-z])\1/

最初のグループ([a-z])と一致することを表すコード\ 1

1
Md. A. Barik

Es2018では、名前付きグループを使ってString.match()を使えるようになりました。正規表現をより明確にしようとしていました。

const url =
  'https://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression?some=parameter';
const regex = /(?<protocol>https?):\/\/(?<hostname>[\w-\.]*)\/(?<pathname>[\w-\./]+)\??(?<querystring>.*?)?$/;
const { groups: segments } = url.match(regex);
console.log(segments);

そして、あなたは何かのようになるでしょう 

{protocol: "https"、hostname: "stackoverflow.com"、pathname: "questions/432493/javascriptの正規表現に一致するグループにアクセスする方法"、querystring: " some = parameter "}

0
David Cheung

すべてのグループオカレンスを取得

let m=[], s = "something format_abc  format_def  format_ghi";

s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.Push(y));

console.log(m);
0