JavaScript regexで文字列を判定・抽出・置換する

JavaScript regex は、パターンに対して文字列を照合し、検証・抽出・置換を行います。入力が日付、ID、コードのように予測可能な形式に従う場面では、正規表現で必要な部分を判定または取り出せます。括弧で作るキャプチャグループは一致した部分文字列を分離するため、文字列を手動で分割しなくても、1つのパターンから構造化データを取得できます。

パターン抽出を行う JavaScript Regex の例

出力:

ここに出力が表示されます...

出力:

日付を含む: true
抽出: 2024/03/15
置換後: 注文 #A-123 は 2024/03/15 に発送されました

この例の仕組み

  1. /(\d{4})-(\d{2})-(\d{2})/ は ISO 形式の日付に一致する正規表現リテラルです。\d{4} は4桁の数字に一致し、括弧は年・月・日を取り出すキャプチャグループを作ります。
  2. datePattern.test(text) は、文字列内のどこかにパターンが一致すれば true を返します。一致の詳細は返しません。
  3. text.match(datePattern) は配列を返します。インデックス 0 に完全一致、その後に各キャプチャグループが入ります。一致しない場合は null なので、ユーザー入力を解析するときは分割代入の前にガードしてください。
  4. text.replace(datePattern, "$1/$2/$3") は一致した部分文字列を置換します。$1$2$3 は各キャプチャグループ(年、月、日)を挿入します。

JavaScript 正規表現とは?

JavaScript の正規表現は、文字列内の文字パターンに一致させるための RegExp オブジェクトです。JavaScript regexp は、リテラル(/pattern/flags)または RegExp コンストラクター(new RegExp("pattern", "flags"))で作成します。エンジンは左から右へ走査し、グローバル(g)フラグがない限り最初の一致を返します。

JavaScript Regex でよくある間違い

testexec でグローバル正規表現を使う。

const re = /\d+/g;
console.log(re.test("abc 123")); // true
console.log(re.test("abc 123")); // false(lastIndex が進んでいる)
re.lastIndex = 0;
console.log(re.test("abc 123")); // true

g または y フラグ付きでは、test/execlastIndex によって状態を持ちます。真偽判定だけなら g を外すか、lastIndex をリセットしてください。

new RegExp() でエスケープを二重にし忘れる。

new RegExp("\d+");  // パターンは "d+"
new RegExp("\\d+"); // 1文字以上の数字

文字列リテラルでは \\ が1つのバックスラッシュになるため、正規表現エンジンには d ではなく \d を渡す必要があります。

正規表現リテラル vs RegExp コンストラクター

正規表現リテラル(/pattern/new RegExp(pattern)
読み込み時に解析され、構文エラーを早期検出できる実行時にコンパイルされ、到達時にエラーが投げられる
文字列エスケープが不要バックスラッシュを二重にする必要がある(\\d
パターンはソースコード内で固定変数からパターンを組み立てられる

静的なパターンにはリテラルを使います。動的な値を含む場合はコンストラクターを使いますが、正規表現インジェクションや意図しないメタ文字解釈を防ぐため、先にユーザー入力をエスケープしてください。

const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const re = new RegExp(escapeRegExp("a+b?"), "i");

その他の例

replaceAll ですべて置換する:

const masked = "カード 4111-1111-1111-1111".replaceAll(/\d{4}/g, "****");
console.log(masked); // "カード ****-****-****-****"

検索引数が正規表現の場合、replaceAll には g フラグが必要です。g を省略すると TypeError が発生します。

matchAll ですべての一致を抽出する:

const tags = [...("#js #regex #es2022".matchAll(/#(\w+)/g))];
console.log(tags.map(m => m[1])); // ["js", "regex", "es2022"]

matchAll は一致配列のイテレーターを返し、各要素にキャプチャグループが含まれます。配列に展開すると、すべての結果へまとめてアクセスできます。

FAQ

JavaScript で正規表現をテストするには?

真偽値だけなら regex.test(string) を使い、一致の詳細が必要なら string.match(regex) を使います。複数一致を取得する場合は、g フラグ付きで string.matchAll(regex) を使うと、キャプチャグループを含む全一致のイテレーターを取得できます。

JavaScript は後読みアサーションをサポートしていますか?

はい。肯定後読み (?<=...) と否定後読み (?<!...) は多くの最新 JavaScript エンジンで使えます。ただし、古いブラウザーや一部の組み込みランタイムでは構文エラーになる可能性があります。

リテラルではなく new RegExp() を使うべきなのはいつですか?

記述時点でパターンが固定されておらず、ユーザー入力の検索語を使うような場面では RegExp コンストラクターを使います。それ以外はリテラルが適しています。二重エスケープを避けられ、構文エラーも実行前に検出できます。