TypeScript実践力を身につける!コードスニペットで学ぶ型付けとインターフェース
今回は、特定文字の検索や置換処理でよく使用される正規表現について学習していきましょう。
本記事では、
「正規表現とは?」「正規表現の作成方法は?」
といった内容から
「正規表現の実践的な使い方は?」
といった内容まで、初級者エンジニア向けに詳しく解説していきます。
1.正規表現とは?
正規表現とは、文字列のパターンを表現する汎用的な記法です。主に文字列から郵便番号や電話番号など、特定文字の検索や置換を行うときに使用されます。
①正規表現の使用例
例えば、文字列中の郵便番号を検出したい場合を考えてみましょう。郵便番号のパターンは”100-0001”のように、”3桁の数字”、”-”、”4桁の数字”となるので、正規表現では以下のパターンで定義します。
^[0-9]{3}-[0-9]{4}$
テキストボックスに入力された文字列が、郵便番号かどうかチェックしたいとき、正規表現を使用するとシンプルなコーディングで実現できます。
2.正規表現の主なパターン
ここでは、よく使用される正規表現を紹介します。
正規表現 | 意味 | 例 |
. | 改行以外の任意の1文字にマッチ | – |
\w | 大文字、小文字の英字、数字、アンダースコアにマッチ | – |
\d | 数字にマッチ | – |
\s | 空白文字にマッチ | – |
| | OR条件として使用 | 0(7|8|9)0の場合、070,080,090にマッチ |
{N} | N回繰り返し | (abc){3}の場合、abcabcabcにマッチ |
{M,N} | M回以上N回以下繰り返し | a{2,4}の場合、aa,aaa,aaaaにマッチ |
[A-Z] | 英大文字A-Zの任意1文字にマッチ | a[A-Z]の場合、aA,aB,aR,aZなどにマッチ |
[a-z] | 英小文字a-zの任意1文字にマッチ | b[a-z]の場合、ba,bb,bg,bxなどにマッチ |
[0-9] | 数字0-9の任意1文字にマッチ | c[0-9]の場合、c0,c3,c8などにマッチ |
* | 直前の文字の0回以上繰り返しにマッチ | a*の場合、’a’や’aaa’などにマッチ |
+ | 直前の文字の1回以上繰り返しにマッチ | ab+の場合、’ab’や’abab’,’abb’などにマッチ |
? | 直前の文字0回 or 1回の出現にマッチ | ba?の場合、’b’や’ba’にマッチ |
^ | 直後の文字が行の先頭にある場合にマッチ | ^Javaの場合、JavaScriptなどにマッチ |
$ | 直前の文字が行の末尾にある場合にマッチ | Script$の場合、JavaScriptなどにマッチ |
これらのよく使用される正規表現を、4つのパターンに分けて見てみましょう。
①特別な意味を持つ文字パターン
特別な意味を持つ文字パターンは、”.”、” \w”、” \d”、” \s”の4つになります。
では、ここで”h1 align=”や”h2 align=”などにマッチするパターンを作成してみましょう。
/h\d\salign=/
”\d”は数字一文字を表し、” \s”はスペースを表します。これらの特別文字と”h”や”align=”の固定文字を駆使して、”h1 align=”や”h2 align=”などに対応しているわけです。
②繰り返しを表すパターン
次は、繰り返しを表すパターンを見ていきましょう。”{}”の中に数字を入れると繰り返し回数を指定できます。
例えば”ISO9001 ISO14001”という文字列から、ISO14001だけを検出するパターンを作りましょう。
/ISO\d{5}/
”ISO”は固定文字とし、14001が5桁の数字なので、” \d{5}”とすることで対応しています。
③任意の文字列を表すパターン
任意の文字列を表すパターンには”*”、”+”、”?” があります。それぞれの違いを確認していきましょう。
/x\d*/
”*”は直前の文字の0回以上繰り返しに対応するため、”x”や”x1”、”x147”、”x258369”などにマッチします。
/x\d+/
”+”は直前の文字の1回以上繰り返しに対応。したがって、”x”にはマッチしません。”x1”、”x987”、”x012345”などにマッチします。
/x\d?/
”?”は直前の文字が0回か1回出現する場合に対応するので、”x”、”x0”などにマッチします。
このように、”*”や”+”は、桁数や文字数が不明な場合に役立ちます。特殊文字にはそれぞれ特徴があるので、よく理解して使いこなせるようになりましょう。
④文字の位置を表すパターン
”^”と”$”は文字の位置を表す特殊文字です。”^”は直後の文字が行の先頭にある場合にマッチし、”$”は直前の文字が行の末尾にある場合にマッチします。
/^PC\d{2}/
”PC01”などにマッチしますが、”Mike’s PC01”にはマッチしません。
/PC\d{2}$/
”Mike’s PC01”にはマッチしますが、”PC100”にはマッチしません。
また、
/^PC\d{2}$/
のように、”^”と”$”で囲むと前後に余計な文字があるとマッチしなくなるので、検出精度がアップします。
3.正規表現の作成方法はふたつ
JavaScriptで正規表現の作成方法はふたつあります。ひとつずつ見ていきましょう。
①正規表現リテラルを使う
/(スラッシュ)で囲まれたパターンは、正規表現リテラルとして使用します。
let reg = /ab*/;
②RegExp オブジェクトのコンストラクタを呼び出す
RegExpオブジェクトのコンストラクタを呼び出す方法もあります。
let reg = new RegExp('ab*');
③使い分け
ここで、正規表現リテラルとRegExpオブジェクト、どちらを使えばいいか説明していきます。
正規表現リテラルはスクリプトがロードされたときにコンパイルされ、RegExpオブジェクトはコンストラクタが呼ばれるときにコンパイルされます。
正規表現パターンが動的に変化するときや、パターン内で変数を使うなど、パターンが変わるとき正規表現リテラルを使用するとパフォーマンスが落ちるので、RegExpオブジェクトのコンストラクタを使う方が良いでしょう。
反対に、正規表現パターンが変化しない場合は、リテラルを使用すると、パフォーマンスが良いです。
④主なオプションフラグ
正規表現にはオプションフラグを付けることが可能です。正規表現リテラルを使用するときは末尾のスラッシュの後に記述し、RegExpオブジェクトを使用するときは第2引数に指定します。
主なオプションフラグは以下の通りです。
オプションフラグ | 説明 |
g | グローバルリサーチ 文字列全体を見つかったすべてのパターンにマッチさせる |
i | 大文字・小文字を区別せずに検索・置換する |
m | 対象のテキストを複数行として扱う |
u | 正規表現パターン内でUnicode値を表現する |
サンプルコードで確認してみましょう。
まずは、オプションフラグがないパターンです。
let str = "ABCD";
let reg = /bc/;
console.log(reg.test(str));
実行結果:
false
通常、正規表現では大文字・小文字を区別するため、文字列”ABCD”は、”bc”とマッチしません。
つぎにオプションフラグiを設定したパターンを見てみましょう。これは、大文字・小文字を区別せずに検索・置換するフラグです。
let str = "ABCD";
let reg = /bc/i;
console.log(reg.test(str));
実行結果:
true
実行結果から、大文字・小文字を区別せずに検索していることがわかりますね。
4.正規表現のエスケープ
ここでは、正規表現のエスケープ処理について学んでいきましょう。
エスケープとは、プログラミング言語にとって特別な意味を持つ文字や記号を、別の文字列に置き換えることです。
①エスケープが必要な場面
前述したように ”. ”、”* ”、”+ ”、”? ”、”| ” などの特殊文字は、パターンの中で記述すると特別な意味を持ちます。これらの特殊文字をパターンの中で通常の文字として認識させるためには、”\”で無効化(エスケープ)させる必要があります。
サンプルで確認しましょう。
let str1 = 'camp.trainocate';
let str2 = 'camp_trainocate';
let str3 = 'camp@trainocate';
let reg = new RegExp(/camp.trainocate/);
let result1 = reg.test(str1);
let result2 = reg.test(str2);
let result3 = reg.test(str3);
console.log(result1);
console.log(result2);
console.log(result3);
実行結果
true
true
true
本来’camp.trainocate’だけマッチしてほしいのですが、”. ”は改行以外の文字はすべて検出するため、’camp_trainocate’や’camp@trainocate’もマッチしてしまいます。このような状況でエスケープ処理を行いましょう。
②バックスラッシュを使ったエスケープ方法
では、実際に”. ”をエスケープしてみましょう。
let str1 = 'camp.trainocate';
let str2 = 'camp_trainocate';
let str3 = 'camp@trainocate';
let reg = new RegExp(/camp\.trainocate/);
let result1 = reg.test(str1);
let result2 = reg.test(str2);
let result3 = reg.test(str3);
console.log(result1);
console.log(result2);
console.log(result3);
実行結果
true
false
false
正規表現パターンの”. ”の前に”\”を記述することで、通常文字”. ”を意味することになったので、’camp_trainocate’や’camp@trainocate’がマッチしないようになりました。
5.正規表現を使うメソッド
この章では、JavaScriptで正規表現を使うメソッドを紹介します。
RegExpオブジェクトのメソッドは次の通りです。
RegExpオブジェクト | 説明 |
test | 文字列中に一致するものがあるかを確認し、結果をtrueまたはfalseで返す |
exec | 文字列中に一致するものがあるかを検索し、結果を配列で返す |
Stringオブジェクトのメソッド一覧です。
Stringオブジェクト | 説明 |
match | 文字列中に一致するものがあるかを検索し、結果を配列で返す |
replace | 文字列中に一致するものがあるかを検索し、一致した文字列を別の文字列に置換 |
search | 文字列中に一致するものがあるかを確認し、一致した文字列の文字位置を返す |
split | 正規表現または固定文字列を区切り文字で分割し、結果を文字列の配列として返す |
各メソッドの使い方を見ていきましょう。
①testメソッドでtrue / falseの取得
let str = '100-0001';
let reg = new RegExp(/^\d{3}-\d{4}$/);
let result = reg.test(str);
console.log(result);
実行結果:
true
このサンプルコードは、文字列strが郵便番号かどうかをチェックします。郵便番号は”(3桁の数字) – (4桁の数字)”のため、正規表現は” ^\d{3}-\d{4}$”です。
testメソッドを使うと、正規表現にマッチする文字列が含まれているか判定できます。
②execメソッドで文字列検索
let str = 'JavaScript Programing';
let reg = new RegExp(/Script/);
let result = reg.exec(str);
console.log(result);
実行結果:
['Script', index: 4, input: 'JavaScript Programing', groups: undefined]
このサンプルコードは、文字列strから”Script”と一致するかを検索しています。
execメソッドを使うと、正規表現にマッチする文字列を検索し、結果を配列で取得できます。
③matchメソッドで文字列検索
let str = 'JavaScript Programing';
let result = str.match(/Script/);
console.log(result);
実行結果:
['Script', index: 4, input: 'JavaScript Programing', groups: undefined]
このサンプルコードは先ほどと同様に、文字列strから”Script”と一致するか検索します。ここでは、Stringオブジェクトのmatchメソッドを使い、パターンには正規表現リテラルを使用しています。
④replaceメソッドで文字列置換
let str = 'index.html';
let result = str.replace(/\.html/,'.js');
console.log(result);
実行結果:
index.js
これは、”index.html” の拡張子 ”.html” を ”.js” に置換するプログラムです。replaceメソッドの第1引数に正規表現パターンを指定し、第2引数に置換する文字列を指定しました。
このように、replaceメソッドは正規表現に一致する文字列を、指定する文字列に置換できます。
⑤searchメソッドで文字の位置を検索
let str = 'camp@trainocate.co.jp';
let result = str.search(/\.co\.jp/);
console.log(result);
実行結果:
15
文字列strから、”.co.jp”と一致する文字列が最初にでてきた位置を取得しています。
⑥splitメソッドで文字列を分割
let str = 'one,two,three';
let result = str.split(/,/);
console.log(result);
実行結果:
['one', 'two', 'three']
文字列str中の”, ”を区切り文字として指定し、文字列を分割。分割結果を配列として返します。
6.実践的な使用方法
ここでは、実際の業務でよく使われる実践的な使用方法を紹介します。
①文字列の抽出
正規表現を使って特定の文字列を抽出してみましょう。
サンプルコードは、日付と時刻の文字列から、日付部分と時刻部分をそれぞれ抽出しています。
let str = 'Date 2022/07/25, Time 12:20:30';
let result = str.match(/\d{4}\/\d{2}\/\d{2}|\d{2}:\d{2}:\d{2}/g);
//戻り値全体を表示
console.log(result);
//ひとつ目に一致した文字列のみを表示
console.log(result[0]);
//ふたつ目に一致した文字列のみを表示
console.log(result[1]);
実行結果:
['2022/07/25', '12:20:30']
2022/07/25
12:20:30
matchメソッドの引数にgオプションを指定しています。最初に一致する文字列を見つけても、検索を続けて、他に一致する文字列をすべて抽出していることがわかりますね。
②全角文字のチェック
入力された内容が全角文字のみかどかをチェックする正規表現のパターンは次の通りです。
/^[^ -~。-゚]+$/
サンプルコードで確認してみましょう。
let str = 'プログラミング 学習';
let result = str.match(/^[^ -~。-゚]+$/);
if (result == null){
console.log("全角文字以外が入力されています。");
}else{
console.log("すべて全角文字です。");
}
実行結果:
すべて全角文字です。
実行結果から、全角スペースも検出されていることがわかりますね。
※掲載された社名、製品名は、各社の商標及び登録商標です。