JavaScript 正規表現で一致したグループにアクセスするにはどうすればよいでしょうか? 質問する

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.logのようにパラメータを受け取りprintf、ログに記録していた文字列 ( "%A") に特殊な値があったため、次のパラメータの値を見つけようとしていたことです。

ベストアンサー1

更新日: 2019-09-10

複数のマッチを反復する従来の方法は、あまり直感的ではありませんでした。このため、String.prototype.matchAllこの新しい方法は、ECMAScript 2020仕様クリーンなAPIを提供し、複数の問題を解決します。主要なブラウザやJSエンジンに採用されています。Chrome 73+ / Node 12+および Firefox 67 以降。

このメソッドはイテレータを返し、次のように使用されます。

const string = "something format_abc";
const regexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
const matches = string.matchAll(regexp);
    
for (const match of matches) {
  console.log(match);
  console.log(match.index)
}

これはイテレータを返すので、遅延型と言えます。これは、特に多数のキャプチャ グループや非常に大きな文字列を処理する場合に便利です。ただし、必要な場合は、スプレッド構文またはArray.fromメソッドを使用して、結果を簡単に配列に変換できます。

function getFirstGroup(regexp, str) {
  const array = [...str.matchAll(regexp)];
  return array.map(m => m[1]);
}

// or:
function getFirstGroup(regexp, str) {
  return Array.from(str.matchAll(regexp), m => m[1]);
}

この提案が幅広い支持を得るまでの間、公式シムパッケージ

また、メソッドの内部動作は単純です。ジェネレータ関数を使用した同等の実装は次のようになります。

function* matchAll(str, regexp) {
  const flags = regexp.global ? regexp.flags : regexp.flags + "g";
  const re = new RegExp(regexp, flags);
  let match;
  while (match = re.exec(str)) {
    yield match;
  }
}

lastIndex元の正規表現のコピーが作成されます。これは、複数の一致を処理するときにプロパティが変化することによる副作用を回避するためです。

また、無限ループを回避するために、正規表現にグローバルフラグがあることを確認する必要があります。

また、このStackOverflowの質問が参照されているのも嬉しいです。提案に関する議論

元の回答

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

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

複数の一致がある場合は、それらを反復処理できます。

var myString = "something format_abc";
var myRegexp = new RegExp("(?:^|\\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);
}

おすすめ記事