JavaScriptにおける正規表現の使い方


ccc

東京都内でサラリーマンをしているAI・育児ブロガー、CCCです。 AI(人工知能)と子育てに関する記事を執筆しています。 WebシステムをベースとしたAIを活用することで生活をより便利にする方法を紹介し、育児について衣食住における役立つグッズや情報を配信しています。


JavaScriptにおける正規表現の使い方を教えてください。


ccc

JavaScript はクライアント側で実行されるオブジェクト指向型のスクリプト言語です。主にブラウザ上で実行され、ユーザのアクションに応じて動的にWebページの内容を書き換えたり、フォームに入力された内容をチェックしたりといったことがクライアント側で実現できます。また、Ajaxという仕組みを利用することで、Webサーバーとブラウザとの間で非同期通信を行えるので、ページを切り替えることなくページの内容を書き換えることができます。Web系AIとJavaScriptの親和性はピカイチで、AIをWebブラウザから使うためのライブラリが公開されています。


ccc

今回はJavaScriptの使い方として、JavaScriptにおける正規表現の使い方をサンプルを用いて解説します。

正規表現オブジェクトを作成

正規表現のパターンをスラッシュ(/)で囲んで、正規表現オブジェクトを作成します。

let regex1=/car/; //"car"とマッチするパターン
let regex2=/[a-zA-Z]{3}/; //アルファベット3文字とマッチするパターン
let regex3=/[0-9a-zA-Z]/; //英数字とマッチするパターン 

メタ文字をエスケープ

アスタリスク(*)など、正規表現で特別な意味を持つ文字をメタ文字といい、単なる文字として扱うときはバックスラッシュ(\)を記述します。

let regex=/\*car/;
let temp="I love driving a *car";
console.log(regex.test(temp));
//true

正規表現にマッチするか調べる

test()は正規表現にマッチするかどうか調べてtrueまたはfalseを返すメソッドです。

正規表現”.”は任意の1文字を意味します。

let regex=/dri.ing/;
let temp="I love driving a car";
console.log(regex.test(temp));
//true

マッチした文字列の次の文字のインデックスを取得(testメソッド)

正規表現のパターンの最後にグローバルフラグ”g”を設定すると、lastIndexプロパティに正規表現とマッチした文字列の次の文字のインデックスが格納されます。その後、同じ文字列に対してtestメソッドを実行すると、現在のlastIndexプロパティのインデックスの位置から検索されて再び正規表現にマッチすると、lastIndexプロパティの値が更新されます。正規表現にマッチしなかった場合、lastIndexプロパティは0に戻ります。

次の例のように、グローバルフラグを設定してlastIndexプロパティを参照すると、同じ文字列に対して正規表現が複数回マッチするかどうか調べることができます。

let regex=/abc/g;
let temp="abcdefgabc";

console.log(regex.test(temp));
console.log(regex.lastIndex);
//true
//3

console.log(regex.test(temp));
console.log(regex.lastIndex);
//true
//10

console.log(regex.test(temp));
console.log(regex.lastIndex);
//true
//0

正規表現にマッチした部分の文字列を取得

exec()は正規表現にマッチした部分の文字列を配列に格納するメソッドです。マッチしなかったときの戻り値はNullになります。
配列のインデックス0の要素にパターン全体にマッチした文字列が格納されます。インデックス1以降の要素に括弧()で囲んだパターンにマッチした部分の文字列が格納されます。

正規表現”\d”は0〜9の数字を意味します。

let regex=/(\d{4}年)(\d{2}月)/;
let temp=regex.exec("2020年12月");
if(temp != null){
 console.log(temp[0]);
 console.log(temp[1]);
 console.log(temp[2]);
}
//2020年12月01日
//2020年
//12月

パターンのグループに名前をつける

括弧()で囲ったパターンのグループに名前をつけることができます。
それぞれのパターンの前に”?<名前>”をつけます。参照するときは、”変数.groups.名前”と記述します。

let regex=/(?<yyyy>\d{4}年)(?<mm>\d{2}月)/;
let temp=regex.exec("2020年12月");
if(temp != null){
 console.log(temp.groups.yyyy);
 console.log(temp.groups.mm);
}
//2020年
//12月

マッチした文字列の次の文字のインデックスを取得(execメソッド)

正規表現のパターンの最後にグローバルフラグ”g”を設定すると、lastIndexプロパティに正規表現とマッチした文字列の次の文字のインデックスが格納されます。その後、同じ文字列に対してexecメソッドを実行すると、現在のlastIndexプロパティのインデックスの位置から検索されて再び正規表現にマッチすると、lastIndexプロパティの値が更新されます。正規表現にマッチしなかった場合、lastIndexプロパティは0に戻ります。

次の例のように、グローバルフラグを設定してlastIndexプロパティを参照すると、同じ文字列に対して正規表現が複数回マッチするかどうか調べることができます。

let regex=/abc/g;
let temp="abcdefgabc";

console.log(regex.exec(temp));
console.log(regex.lastIndex);
//true
//3

console.log(regex.exec(temp));
console.log(regex.lastIndex);
//true
//10

console.log(regex.exec(temp));
console.log(regex.lastIndex);
//true
//0

正規表現にマッチした文字列のインデックスを取得

search()は正規表現にマッチした文字列の先頭のインデックスを取得するメソッドです。マッチしないとき-1を返します。
正規表現”+”は直前の文字の1回以上の繰り返しを意味します。

let regex=/def.+klm/;
let temp="abcdefghijklmnopqrstu";
console.log(temp.search(regex));
//3

正規表現がマッチする全ての文字列を取得

match()は、正規表現にグローバルフラグ”g”を設定されているとき、正規表現がマッチする全ての文字列を配列に格納するメソッドです。マッチしないときはNullを返します。

let regex=/\d{4}年\d{2}月/g;
let str="2020年12月 2021年01月";
let temp=str.match(regex);

if(temp != null){
 console.log(temp[0]);
 console.log(temp[1]);
}
//2020年12月
//2021年01月

正規表現を使った区切り文字で分割

spilit()は正規表現を使った区切り文字で文字列を分割できるメソッドです。
正規表現”[ ]”は括弧の中のどれか1文字を意味します。

let temp="123,456.789";
let temp2=temp.split(/[,.]/);
console.log(temp2);
["123", "456", "789"]

正規表現にマッチした文字列を別の文字列に置き換える

replace()は正規表現にマッチした文字列を別の文字列に置き換えるメソッドです。
正規表現”|”は複数の文字列のいずれかを意味します。

let regex=/car|truck/;
let temp="I love driving a car";
let temp2=temp.replace(regex, "vehicle");
console.log(temp2);
//I love driving a vehicle

正規表現にグローバルフラグ”g”を設定すると、正規表現にマッチする全ての文字列が置換されます。

let regex=/car/g;
let temp="car cat car cat";
let temp2=temp.replace(regex, "vehicle");
console.log(temp2);
//vehicle cat vehicle cat

括弧()で囲んだパターンにマッチした部分の文字列を”$数字”で取得することもできます。

let regex=/(\d{4})年(\d{2})月/;
let temp="2020年12月";
let temp2=temp.replace(regex, "$1年$2月");
console.log(temp2);
//2020年12月

関数を使って正規表現にマッチした文字列を置き換えることもできます。
正規表現”[^]”は括弧の中にない1文字を意味します。

let temp="car cat car cat";
let temp2=temp.replace(/[^car]/g, value=>{
return value.toUpperCase();
});
console.log(temp2);
//car caT car caT

正規表現の略記

正規表現を略して記述することができます。

\d //数字 [0-9]を意味する
\D //数字以外 [^\d]を意味する
\w //英数字とアンダーバー [0-9a-zA-Z_]を意味する
\W //英数字とアンダーバー以外 [^\w]を意味する

正規表現の特殊文字

次のような正規表現の特殊文字があります。

\0 //NULL
\n //改行
\t //タブ

文字列の先頭や末尾などにマッチする正規表現

文字列の先頭や末尾などにマッチする正規表現があります。

^ //文字列の先頭にマッチ /^abc/
$ //文字列の末尾にマッチ /abc$/
\b //単語の先頭または末尾にマッチ /\babc/ /abc\b/ /\babc\b/
\B //単語の先頭または末尾以外にマッチ /\Babc/ /abc\B/ /\Babc\B/

直前の文字を指定回数繰り返す正規表現

直前の文字を指定回数だけ繰り返す正規表現があります。

* //直前の文字を0回以上の繰り返す
+ //直前の文字を1回以上の繰り返す
? //直前の文字が0回または1回出現
{3} //直前の文字を3回繰り返す
{3,} //直前の文字を3回以上繰り返す
{,3} //直前の文字を3回以下繰り返す
{3,6} //直前の文字を3回以上6回以下繰り返す
.* //任意の文字を0回以上繰り返す
/(\d{1,3}){3}/ //1~3文字の数値を3回繰り返す

量を表す正規表現でより多い文字列とマッチする

“+”や”*”など量を表す正規表現を使うと、デフォルトでより多い文字列とマッチしようとします。

let regex=/a.+b/;
let temp="aabaaab";
let temp2=temp.match(regex);
console.log(temp2[0]);
//aabaaab

let regex=/a.*b/;
let temp="aabaaab";
let temp2=temp.match(regex);
console.log(temp2[0]);
//aabaaab

let regex=/\d{1,5}/;
let temp="123456789";
let temp2=temp.match(regex);
console.log(temp2[0]);
//12345

量を表す正規表現でより少ない文字列とマッチする

“+”や”*”などの量を表す正規表現を使うとき、正規表現”?”を記述するとより少ない文字列とマッチします。

let regex=/a.+?b/;
let temp="aabaaab";
let temp2=temp.match(regex);
console.log(temp2[0]);
//aab

let regex=/a.*?b/;
let temp="aabaaab";
let temp2=temp.match(regex);
console.log(temp2[0]);
//aab

let regex=/\d{1,5}?/;
let temp="123456789";
let temp2=temp.match(regex);
console.log(temp2[0]);
//1

正規表現の先読みと後読み

正規表現の先読みと後読みはマッチするかどうか確認はするがマッチした文字列として取得しないときに使います。

先読みの正規表現では取得する文字列を先に記述し、”(?=)”または”(?!)”を後に記述します。
“(?=)”は肯定を表し、”(?!)”は否定を表します。

let regex=/abc(?=def)/; //abcの後にdefがあるときマッチ
let temp=regex.exec("abcdef");
console.log(temp[0]);
//abc

let regex=/abc(?!def)/; //abcの後にdefがないときマッチ
let temp=regex.exec("abcdez");
console.log(temp[0]);
//abc

後読みの正規表現では”(?<=)”または”(?<!)”を前にに記述し、取得する文字列を後に記述します。
“(?<=)”は肯定を表し、”(?<!)”は否定を表します。

let regex=/(?<=abc)def/; //defの前にabcがあるときマッチ
let temp=regex.exec("abcdef");
console.log(temp[0]);
//def

let regex=/(?<!abc)def/; //defの前にabcがないときマッチ
let temp=regex.exec("abzdef");
console.log(temp[0]);
//def