JavaScriptを使っている際に、文字列の検索や抽出を行いたい場合があります。本記事ではそのような場面で便利な正規表現を扱うことのできるJavaScriptのRegExpオブジェクトについて実装例を交えて解説します。正規表現を用いない文字列操作については「JavaScriptの文字列操作について解説(検索、比較、結合、置換、分割、型変換)」を参考にしてみてください!
正規表現(RegExp)とは?
正規表現は文字列のパターンを表現して文字列内での文字の検索や抽出、置換、分割を行いやすくするものです。言語にかかわらず正規表現の決まりがありますが言語によって多少の仕様の違いがあります。JavaScriptではRegExpオブジェクトを用いることで正規表現を扱うことができます。
正規表現のパターン
正規表現によるパターンの紹介をします。今回紹介するものが全てではないですが、基本的な実装には十分なパターンを紹介します。
基本のパターン表記
次に基本のパターンを表にしています。
文字列パターン(基本) | マッチする文字列 | 説明 |
abcd | abcd | 文字列はそのままマッチします |
[abcd] | a,b,c,dの中の1つ | []でくくると[]から1文字選びます |
[ABcd] | A,B,c,dの中の1つ | 大文字と小文字は区別します |
[a-f] | a,b,c,d,e,fから1つ | []内部で-でつなぐと順番のすべてを意味します |
[a-z] | 半角英字全ての文字の中から1つ | []内部で-でつなぐと順番のすべてを意味します |
[0-9] | 0から9までの半角数字の中から1つ | 数字も-でつなぐことができます |
[^a] | a以外の任意の1文字 | []内部で^は[]内部の文字以外を指定します |
[^a-z] | 半角英字以外の全ての文字の中から1つ | []内部で^は[]内部の文字以外を指定します |
a|b|c | a,b,cの中の1つ | |はいずれかの条件であることを意味します |
ab|cd | abまたはcd | |はパターンも条件に含めます |
a(bc|de) | abcまたはade | |はパターンも条件に含めます |
これらの基本的な表記に加えて、次のような文字セットと呼ばれる省略した記法があります。
文字列パターン(文字セット) | マッチする文字列 | 説明 |
. | 全ての文字1文字 | |
\w | 半角大文字小文字英数字と_から1文字 | |
[\w$%&] | 半角大文字小文字英数字と_,$,%,&から1文字 | 他の文字と併用することもできます |
\w | 半角大文字小文字英数字と_以外から1文字([^\w]または[^a-zA-Z0-9_]) | |
\d | 数字1文字([0-9]) | |
\D | 数字以外から1文字([^0-9]) | |
\s | 空白文字1文字 | |
\S | 空白文字以外から1文字 | 空白文字とはスペース、改行、復帰、タブ等の総称です |
\n | 改行1回分 |
また、文字列の先頭や末尾を指定できる位置指定のパターンもあります
文字列パターン(位置指定) | マッチする文字列 | 説明 |
^ | 行の先頭 | ^は文字列の先頭の文字の前にある文字のない部分に一致します |
^abc | 行の先頭からabcと続く文字列 | ^は文字列の先頭にある後にある文字のない部分に一致します |
$ | 行の末尾 | $は文字列の末尾にある後にある文字のない部分に一致します |
abc$ | abcの次に行の末尾が来る文字列 | $は文字列の末尾にある後にある文字のない部分に一致します |
さらに文字のマッチをする回数を指定できる量指定を記述するパターンもあります
文字列パターン(位置指定) | マッチする文字列 | 説明 |
a* | aに0回以上 | *は0回以上を指定します |
a+ | aに1回以上 | +は1回以上を指定します |
a? | aに0回または1回 | ?は0回または1回を指定します |
a{2} | aに2回以上 | {n}でn回(ちょうど)を指定できます |
a{2,6} | aに2回以上6回以下 | {m,n}はm回以上n回以下を指定できます |
a{2,} | aに2回以上 | {n,}でn回以上を表します |
\w+ | 半角大文字小文字英数字と_1文字以上 | 文字セットにも量指定のパターンは適用できます |
(\w[./-])* | 半角大文字小文字英数字と_1文字と.(ドット)または/または-のセット0回以上 | ()でくくったグループにも量指定のパターンは適用できます |
エスケープが必要な文字
すでに紹介した.や?などの特殊文字は正規表現の中で指定する際にエスケープ処理をする必要があります。エスケープはバックスラッシュ\を特殊文字の前に表記するだけです。例えばGoogle.comを文字列指定したい場合は次のように表現します。
Google\.com
エスケープ処理が必要な特殊文字は次のものです
. * + ^ | [ ] ( ) ? $ { }\
[]内部では特殊文字が別になること、さらに言語の使用によって予約語があるためそれらの文字についてもエスケープ処理があることに注意が必要です
[]内部でのエスケープ
「[]」内部ではで紹介した特殊文字とは別の文字が特殊文字として扱われるので.や?などはエスケープする必要は無くなります。代わりに次の文字をエスケープする必要があります。
-\^]
これらの文字であってもエスケープしなくて良い場合があります
- 「-」は文字間にない場合つまり、[]内部の最初か最後にある場合はエスケープが不要です
- 「\」はどの場合であってもエスケープ処理をして\\と表記します
- 「]」は[]内部ではエスケープする必要はありません(閉じタグが二つになり不自然な表記になりますが、機能します)
- 「^」は[]の先頭になければ特殊文字としての意味を持たないためそれ以外の場所ではエスケープする必要はありません
「[]」ではこのように通常とは異なるエスケープ処理をします
代表的な正規表現での文字列パターン
正規表現のいくつかのパターンを紹介します。コピペして使用するのではなく、意味を理解した上で利用することをお勧めします。特にEmailアドレスやURLは仕様を完全に網羅しているわけではないため注意が必要です。
郵便番号の正規表現
[0-9]{3}-[0-9]{4}
郵便番号はシンプルな連番で3桁の数字と4桁の数字が-で繋がっている文字列パターンを表現しています。
- [0-9]は0から9の半角数字が一つあることを意味します。
- {3}は直前の[0-9]のパターンが3回繰り返されることを意味します
- -はハイフンがあることを意味します
Emailアドレスの正規表現
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
Emailアドレスの文字列パターンを表現する際に本来の仕様通りにすると複雑になってしまうので、簡易バージョンを取り上げました。基本的には〇〇@〇〇.〇〇のパターンでなければならないことを意味します。
- \w+は大文字小文字の英数字アンダーバーが1文字以上あることを意味します
- ([-+.]\w+)*は-,+,.から一文字([-+.])と大文字小文字の英数字アンダーバー(\w)1文字以上(+)によるセット(([-+.]\w+))が0個以上あること(*)を意味しています。
- @は@マークがあることを意味しています
- \.はドットがあることを意味しています
URLの正規表現
https?://([\w-]+\.)+[\w-]+(/[\w- .?%&=]*)?
こちらも本来の仕様通りにすると複雑になってしまうので、簡易バージョンを取り上げました。
- https?はsが0または1文字あることを意味しますしたがってhttpsでもhttpでも良いということです。(http|https)のような書き方もできます
- [\w]は大文字小文字の英数字アンダーバーから1文字ということを意味しています
- (/[\w-.?%&=]*)?は/と大文字小文字の英数字アンダーバー(\w)または-,?,%,&,=の中から0文字以上のセット(/[\w- .?%&=]*)が0または1組あることを意味します
JavaScriptでの正規表現の使い方
正規表現の基本的な使い方がわかっている前提でJavaScriptでの正規表現の使い方について説明します。まずは、正規表現を扱うRegExpオブジェクトの宣言方法を説明し、そのあとmatchメソッドを使ったRegExpオブジェクトの使い方を実装例を交えて紹介します。
RegExpオブジェクトの使い方
JavaScriptでは正規表現をRegExpオブジェクトで表現した型で扱うことができます。RegExpオブジェクトを生成する方法は二つあり
- コンストラクター経由で宣言する方法
- 正規表現リテラルを利用する方法
の二種類です。
コンストラクター経由では次のように文字列リテラルでの正規表現を引数に入れて宣言します
const regexp = new RegExp('正規表現')
この際に\が文字列リテラルでは予約語になっているため、\でエスケープする必要があります。
一方で正規表現リテラルを利用する場合は次のように宣言します
const regexp = /正規表現/
このように//で正規表現を囲むことでRegExpオブジェクトを生成できます。この際に正規表現リテラルでは/が予約語になっているため、\でエスケープする必要があります。
matchメソッドの基本的な使い方
JavaScriptで文字列を扱うStringオブジェクトのメソッドにmatchというものがあり、これを用いることで文字列内から正規表現で記述された特定の文字列パターンを抽出することができます。
検索対象の文字列.match("正規表現")
matchメソッドはRegExpオブジェクトで宣言された変数を引数にもちます。戻り値として、抽出された文字列を配列形式で返します。したがって、抽出された文字を使用したい場合には配列の番号を指定する必要があります。抽出できなかった際にはnullが返されます。
JavaScriptの正規表現の実装例(match)
実際に正規表現とStringオブジェクトのmatchメソッドを用いて入力のバリデーション機能を実装してみましょう。バリデーションとはユーザーの入力が適切な形式になっているかをチェックすることを意味します。次のような機能を実装します。
メールアドレスの入力が正しく行われると、送信済みの表示がされます。一方でメールアドレスの入力が正しく行われないと次のようにアラートが表示されます。
まずはコードを確認してみましょう。ファイルは次のような階層になっています。
root/ ├ index.html └ main.js
(index.html)
<body> <input id="form_input" type='text' placeholder="メアドを入力"> <button id="submit_button">送信</button> <div id='display'></div> <script src="./main.js"></script> </body>
index.htmlでは入力フォーム(id="form_input")とボタン(id="submit_button")と送信完了を表示するディスプレイ(id='display')を記述しています。
(main.js)
const form_input = document.getElementById("form_input") const submit_button = document.getElementById("submit_button") const display = document.getElementById("display") const mail_regexp = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/ submit_button.addEventListener("click", () => { if (form_input.value.match(mail_regexp) == null) { alert("メールアドレスが正しくありません") } else { display.innerHTML = form_input.value.match(mail_regexp) + "に送信済み" } })
動作は次のサイトで確認できます。
main.jsでは要素の取得と、ボタンのクリックに対するハンドラとしてmatchメソッドを用いたバリデーションを実装しています。詳しく解説していきます。
まず、mail_regexpにメールアドレスの文字列パターンを正規表現リテラルで代入します。
const mail_regexp = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/
文字列パターンの書き方についてはすでに説明しているので省略します。
ボタンのクリックに対するハンドラ関数内では、次のようにして入力したフォーム内にmail_regexpで定義した文字列パターンがあるかどうかをmatchメソッドでチェックします。
if (form_input.value.match(mail_regexp) == null){}
matchメソッドは文字列オブジェクトのメソッドです。form_input.valueではインプットフォーム内の値が文字列として代入されています。matchメソッドは文字列内に指定した文字列パターンがなければnullを返すため、今回のif文内ではnullだった場合にアラートさせるように実装しています。
正規表現で文字列を置換する(replace)
replaceメソッドの基本的な使い方
文字列オブジェクトに含まれているreplaceメソッドを用いて文字列内部の任意の文字列を別の文字列に置換することができます。正規表現を用いなくても文字の置換を行うことはできますが、正規表現を用いたほうがより広範な文字列置換を実装できます。
置換対象の文字列.replace("正規表現","置換後の文字列")
replaceメソッドはこのように書きます。置換が行われた後の文字列が戻り値として返ってきます。
サブマッチ文字列を用いた実装例(アンカータグの自動生成)
サブマッチ文字列とは正規表現を宣言した際に()で囲まれた部分にマッチした文字列のことです。matchメソッドの戻り値やreplaceメソッドの第二引数で使用することができます。本項ではreplaceメソッドとサブマッチ文字列を用いてアンカータグの自動生成を行う機能を実装します。
文章内のURLをアンカータグつきにしてテクストにして表示するものです。コードを確認してみましょう。ファイルは次のような階層になっています。
root/ ├ index.html └ main.js
(index.html)
<body> <textarea id='textarea' cols='30' rows='10'></textarea> <button id='button'>aタグ生成</button> <div id='display'></div> <script src="./main.js"></script> </body>
index.htmlでは元の文章を記入するテキストエリアとボタン、アンカータグの文章を出力するディスプレイを配置します。
(main.js)
const display = document.getElementById('display') const button = document.getElementById('button') const textarea = document.getElementById('textarea') const regex = new RegExp('(https?://([\\w-]+\\.)+[\\w-]+(/[\\w- .?%&=]*)?)') button.addEventListener('click', () => { str = textarea.value display.innerHTML = str.replace(regex, '<a href="$1">$1</a>') })
動作は次のサイトで確認できます。
mian.jsではHTML要素を取得したのち、URLの文字列パターンを表現したregexをコンストラクターで生成します。ボタンのハンドラ関数内でreplaceメソッドを利用してテキストエリア内の文字のなかで、URLの部分をaタグで置換していきます。この際に$1で表記している部分があります。これがサブマッチ文字列にあたります。replaceメソッドではサブマッチ文字列の要素を順に$n(n=0,1...)で表します。今回はURL全体の文字列パターンを()でくくっているので、サブマッチ文字列の$1がURL全体を示しています。
正規表現で文字列を分割する(split)
splitメソッドの基本的な使い方
文字列オブジェクトに含まれているsplitメソッドを用いて文字列を分割することができます。正規表現を用いなくても文字の分割を行うことはできますが、正規表現を用いたほうがより広範な文字列分割を実装できます。
分割対象の文字列.splice(正規表現)
splitメソッドはこのように書きます。分割後の配列が戻り値として返ってきます。
splitメソッドの実装例(文章を単語に分割する)
今回は英語の文章を単語で区切って配列にする機能を実装しましょう。次のようなものを作ります。
コードを確認してみましょう。ファイルは次のような階層になっています。
root/ ├ index.html └ main.js(index.html)
(index.html)
<body> <textarea id='textarea' cols='30' rows='10'></textarea> <button id='button'>単語の配列生成</button> <div id='display'></div> <script src="./main.js"></script> </body>
index.htmlでは元の文章を記入するテキストエリアとボタン、分割された配列を出力するディスプレイを配置します。
(main.js)
const display = document.getElementById('display') const button = document.getElementById('button') const textarea = document.getElementById('textarea') const regex = /[^\w-$'&]+/ button.addEventListener('click', () => { sentences = textarea.value words = sentences.split(regex); console.log(words) display.innerText = words })
main.jsではHTMl要素の取得をし、分割に用いるRegExpオブジェクトを正規表現リテラルを用いて生成しています。ボタンのハンドラ関数ではテキストエリア内の値を文字列として代入し、先ほど生成したRegExpオブジェクトで分割し、コンソールとdisplayに表示しています。
この記事のまとめ
本記事ではJavaScriptでの正規表現の扱いを、実際の実装例を元に説明しました!最後に記事の要点をまとめてみましょう。
- 正規表現を用いることで正規表現のパターンを用いて文字の検索や置換、分割ができる
- 正規表現はRegExpオブジェクトで扱う
- RegExpオブジェクトのコンストラクタを用いる場合と正規表現リテラルを用いる場合がある
- JavaScriptでの予約語のエスケープに注意する
- 文字列オブジェクトのmatchメソッド、replaceメソッド、splitメソッドでも正規表現を用いることができる
JavaScriptでの正規表現を是非活用してみましょう。