正規表現の使い方

指定した文字列を検索したり、置換したりできると便利です。

本ページでは、正規表現について説明します。

正規表現とは

正規表現とは、文字列のパターンを示す表現方法です。

例えば、if ( x === "abc" )と条件分岐させる時、xが"abc"の時だけがtrueになり、xが"abcd"の時はfalseになります。

正規表現を使えば、xが"abc"を含めばtrueなどといった条件分岐が可能になります。

正規表現の説明

この場合、xが"abcd"でもtrueになります。

正規表現の記述方法

正規表現の記述方法は、2とおりあります。正規表現リテラルと、RegExpのコンストラクタ関数を使う方法です。次からは、それぞれの記述方法を説明します。

正規表現リテラルで記述する方法

正規表現リテラルは、以下のように記述します。

【正規表現リテラルの記述例】
let x = /abc/;

スラッシュ(/)でパターンを囲みます。上記であれば、文字列"abc"が含まれるパターンということになります。

この方法は、スクリプトが読み込まれた時にコンパイル(実行できるように翻訳)されるため、実行時間が速くなります。このため、通常はこちらを使います。

RegExpのコンストラクタ関数を使う方法

RegExpのコンストラクタ関数を使う方法は、以下のとおりです。

【RegExpのコンストラクタ関数を使った正規表現の記述例】
let x = new RegExp("abc");

ダブルクォーテーション(")かシングルクォーテーション(')でパターンを囲みます。

この方法は、実行する時にコンパイルされるため、実行時間が遅くなります。例えば、for文などで繰り返すと、そのたびにコンパイルが発生します。

毎回コンパイルが発生するのは、メリットもあります。例えば、let x = new RegExp(y)などと、パターンに変数(この場合はy)が使えます。この変数yは、事前にlet y;などで宣言が必要ですが、パターンは代入されていなくてもエラーになりません。このため、最初は代入されていなくて、途中でユーザーが入力した文字や代入される文字列などをパターンにすることができます。

正規表現の利用方法

正規表現の利用方法は、以下のとおりです。

【正規表現の利用方法】
let x = /abc/;
let z = x.test(y);

testは、文字列が含まれていればtrue、含まれていなければfalseを返すメソッドです。このため、上記でyに"abc"が含まれていればzは"true"になり、含まれていなければ"false"になります。

これは、1行目をRedExpで記述した場合でも、使い方は同じです。

if文での利用例は、以下のとおりです。

【if文での正規表現利用例】
let x = /abc/;
if ( x.test(y) ) {
・・・
}

yに"abc"が含まれていれば、trueで処理されます。含まれていなければ、if文の中の処理は実行されません。

また、以下のようにも記述できます。

【正規表現リテラルでの利用例】
if ( /abc/.test(y) ) {
・・・
}

変数を使わずに、直接正規表現を記述して使っています。

メソッド

正規表現は、すでに説明したtestなどのメソッドといっしょに使います。

正規表現は、正規表現.メソッドの形で使う

以下は、メソッドの一覧です。

【正規表現で使えるメソッド】
メソッド 説明
test パターンが一致すればtrue、一致しなければfalseを返します。
exec パターンが一致すればその文字列を配列で、一致しなければnullを返します。
search 一致したパターンが左から何番目に含まれているかを返します。一番左を0とします。一致しなければ-1を返します。
match パターンが一致すればその文字列を配列で、一致しなければnullを返します。
matchAll パターンが一致すればその文字列を配列で、一致しなければnullを返します。複数一致すれば、すべて対象になります。
replace パターンに一致した文字列を置換します。一致しなければ置換しません。
split パターンに一致した文字列を区切りとして配列にします。一致しなければ区切りません。

次からは、各メソッドの利用例を示します。利用例は、リテラルで記述していますが、/ab/などの部分を変数に変えればRedExpで記述した場合でも同じように使えます。

test

testメソッドの利用例は、以下のとおりです。

【testメソッドの利用例】
let z = /ab/.test(y);

上記は、以下の判定になります。

  • yが文字列abを含めば、zはtrue
  • yが文字列abを含まなければ、zはfalse

例えば、yが"abcd"の時はzが"true"になります。yが"efgh"の時は、zが"false"になります。

execとmatchメソッド

execとmatchメソッドの利用例は、以下のとおりです。

【execとmatchメソッドの利用例】
let z = /ab/.exec(y);
let z = y.match(/ab/);

上記の結果はどちらも同じで、以下の判定になります。

  • yが文字列abを含めば、z[0]はab
  • yが文字列abを含まなければ、zはnull

例えば、yが"abcd"の時はz[0]が"ab"になります。yが"efgh"の時は、zがnullになります。

一致した文字列すべてではなく、一部の一致した文字列を抜き出して配列に入れることもできます。以下のように記述したとします。

【execメソッドで()の利用例】
let y = "abcdefghi";
let z = /(a.)cd(e.)/.exec(y);

()内はグループ化されて、記憶されます。また、ドット(.)はすべての1文字と一致します。

zは配列で、以下のようになります。

  • z[0] === "abcdef"
  • z[1] === "ab"
  • z[2] === "ef"

配列の0番目に、パターン全体に一致した文字列が入ります。1番目は、()内の記述と一致した文字列です。今回の例では、(a.)と一致するのは"ab"ということです。2番目は、次の()内の記述と一致した文字列です。今回の例では、(e.)と一致するのは"ef"ということです。

このように、()でグループ化してその内容を配列の要素に代入できます。

searchメソッドの利用例は、以下のとおりです。

【searchメソッドの利用例】
let z = y.search(/ab/);

上記は、以下の判定になります。

  • yが文字列abを含めば、zは先頭からのabがある場所
  • yが文字列abを含まなければ、zは-1

例えば、yが"abcd"の時はzが0、yが"efabcd"の時はzが2、yが"efgh"の時はzが-1になります。

matchAll

matchAllメソッドの利用例は、以下のとおりです。

【matchAllメソッドの利用例】
let y = "abcdefghi a1cde2ghi";
let z = [...y.matchAll(/(a.)cd(e.)/g)];

matchAllは、イテレーター(反復処理して複数の値を取り出せる集合)を返します。イテレーターは順次値を取り出せるため、...ですべての値を取り出しています。これは、スプレッド構文と呼ばれます。

/ab/の後にあるgは、フラグと呼ばれます。gフラグであれば、1回一致してやめるのではなく、何回一致してもすべての値を返します。

このため、zは以下になります。

  • z[0] === ["abcdef", "ab", "ef"]
  • z[1] === ["a1cde2", "a1", "e2"]

z[0]には最初に一致した情報、z[1]は次に一致した情報が入ります。

z[0]で言えば、"abcdef"は最初にパターン全体に一致した文字列です。"ab"と"ef"は()内の記述と一致した文字列です。z[1]の"a1cde2"は、次に一致した文字列です。"a1"と"e2"はその中で()内の記述と一致した文字列です。

つまりmatchALLを使えば、一致した全体の文字列と、グループ化した文字列を配列に入れますが、その組み合わせが複数あってもすべて多次元配列で取り込めるということです。

zは、多次元配列で以下のようになっています。

z === [
["abcdef", "ab", "ef"],
["a1cde2", "a1", "e2"]
]

replace

replaceメソッドの利用例は、以下のとおりです。

【replaceメソッドの利用例】
let z = y.replace(/ab/,"12");

上記は、以下の処理を行います。

  • yが文字列abを含めば、abを12に置換
  • yが文字列abを含まなければ、置換されない

例えば、yが"abcd"の時は先頭の"ab"を"12"に置換してzが"12cd"となります。yが"efgh"の時は、置換せずにzは"efgh"のままになります。

split

splitメソッドの利用例は、以下のとおりです。

【splitメソッドの利用例】
let z = y.split(/-/);

上記は、以下の処理を行います。

  • yが文字列-を含めば、それを区切りに文字列を分解して配列に入れる
  • yが文字列-を含まなければ、分解しない

例えば、yが"ab-cd-ef"の時、zは以下の配列になります。

  • z[0] === "ab"
  • z[1] === "cd"
  • z[2] === "ef"

-で区切られた文字列が、順番に配列に入っています。let z = y.split(/-/,2)と記述すると、2つめの一致までが配列に入ります。つまり、zは["ab", "cd"]になります。

区切るのは"-"とは限らず、英数字や半角スペースなどで区切ることもできます。

exec、match、matchAllメソッドの使い分け

exec、match、matchAll(配列にした場合)は一致する文字列を抜き出すために使いますが、それぞれ違いがあります。

以下は、パターンが/(a.)cd(e.)/、対象の文字列が"abcdefghi a1cde2ghi"だった場合で、gフラグがない時とある時で結果の値を比較しています。

【exec、match、matchAllの値の違い】
メソッド gフラグなし gフラグあり
exec ["abcdef", "ab", "ef"] ["abcdef", "ab", "ef"]
match ["abcdef", "ab", "ef"] ["abcdef", "a1cde2"]
matchAll エラー [
["abcdef", "ab", "ef"],
["a1cde2", "a1", "e2"]
]

それぞれ、以下の特長があります。

exec
execは、gフラグがあってもなくても、最初に一致した文字列と()内の文字列を配列に入れます。このため、複数の一致した文字列を、一度に配列に入れたい時は使えません。
match
matchは、gフラグがないとexecと同じです。gフラグがあると、一致するすべての文字列が配列に入りますが、()内の文字列は配列に入りません。このため、複数の一致した文字列を一度に配列に入れたい時に使えます。
matchAll
matchAllは、一致するすべての文字列も()内の文字列も配列に入りますが、gフラグを使わない場合はエラーになります。このため、複数の一致した文字列だけでなく、()内の一致した文字列も配列に入れたい時に使えます。