今回は、さまざまな文字列パターンを記述できる正規表現について学習をしていきましょう!
「正規表現を使った具体的な活用方法が知りたい」
「正規表現メソッドの種類と使い分けってどうやるの?」
このような内容も含めて、本記事では以下のような構成で解説していきます!
- 【基礎】「正規表現」とは?
- 【基礎】「正規表現」のパターンについて
- 【実践】「正規表現」の活用事例
- 【実践】「正規表現」で使えるメソッド
この記事で、正規表現をしっかり学習してスキルアップを目指していきましょう!
正規表現とは?
正規表現は、特殊な文字を組み合わせて「パターン」を作ることで、そのパターンに適合した特定の文字を検出することができるようになります。
いきなりですが、次の例を見てください。
//正規表現のパターン例 /^\d{3}-?\d{4}$/
恐らく、意味不明な文字の羅列にしか見えないと思いますが、実は、このパターンは「郵便番号」を表しています。郵便番号(123-4567)の組み合わせパターンというのは…
「3桁の数値」「-(ハイフン、ない場合もある)」「4桁の数値」
このような形式が一般的なわけですが、先程の正規表現はまさにこのパターンを表した文字列ということになります。
例えば、HTMLフォームなどでユーザーに郵便番号を入力してもらう時に、正しく入力されているかをチェックするプログラムは、先程の正規表現を使うと非常に簡単なコードで実現します。
const postcode = '123-4567'; const result = postcode.match(/^\d{3}-?\d{4}$/); //パターンに適合しなければreusltはnullになる
変数「postcode」に郵便番号が格納されているので、これに「match()」を使って正規表現を当てはめるだけで、正しい郵便番号なのかどうかをチェックすることが可能になります。
ちなみに、正規表現を使わずにプログラムしようとすれば、非常に複雑なコードになり、バグも発生しやすくなります。
主な正規表現の記号と意味については以下の表の通りです。
記号 | 記号の説明 | 例 | 例の説明 |
---|---|---|---|
. | 任意の1文字。改行文字は除く。 | .+ | 任意の文字列 |
* | 直前の1文字の0回以上の繰り返しと一致 | hoge* | hogeもしくはhogee...と一致 |
^ | 行の先頭 | ^[0-9] | 行頭が数字 |
$ | 行の末尾 | ^.{10}$ | 10文字の行 |
[ ] | カッコ内の任意の1文字と一致。「-」で範囲指定可。 | [a-z] | 小文字のアルファベット1文字と一致 |
[^ ] | カッコ内の任意の1文字と不一致。「-」で範囲指定可。 | [^A-Z] | 大文字のアルファベット以外 |
+ | 直前の文字の1個以上の繰り返しと一致 | hoge+ | hogee...と一致 |
? | 直前の文字が0個または1個の場合に一致 | hoge? | hogeもしくはhogと一致 |
{ } | カッコ内の数値の繰り返しと一致 | {n} | 直前の文字のn個の繰り返しと一致 |
同上 | {,n} | 直前の文字のn個以下の繰り返しと一致 | |
同上 | {m,} | 直前の文字のm個以上の繰り返しと一致 | |
同上 | {m,n} | 直前の文字のm個以上、n個以下の繰り返しと一致 | |
| | 直前、直後どちらかのパターンに一致 | hoge|piyo | hogeまたはpiyo |
( ) | カッコ内をグループ化。マッチした内容は参照可。 | ー | ー |
基本的な正規表現の使い方!
ここからは、実際にJavaScriptで正規表現をプログラミングする方法について学んでいきましょう!方法としては2種類あります。
1つ目は、正規表現のパターンを直接指定する「リテラル」を使った方法です。先ほどの郵便番号を使った例で確認してみましょう!
const regexp = /^\d{3}-?\d{4}$/;
このように、JavaScriptでは/・・・/と囲むことで、その中身は正規表現のパターンとして認識されるわけです。
2つ目の方法は、「RegExp」コンストラクタを使うことです!
const regexp = new RegExp('^\\d{3}-?\\d{4}$');
このようにRegExp()の引数へ文字列の正規表現パターンを指定すれば認識されます。(文字列の場合は「\d」ではなく「\\d」になります)
どちらの方法を使っても結果は同じなのですが、それぞれにメリット・デメリットが存在するので使い分けが重要です。
プログラムの途中で正規表現のパターンを変更する場合や、外部から取得もしくは入力要素から受け取る場合は「RegExp」コンストラクタを使います。逆に、正規表現のパターンがまったく変わらないという場合は「リテラル」を使った方法が好ましいです。
より詳しいRegExpコンストラクタによる正規表現の作り方や活用方法については、次の記事で解説しているのでぜひ参考にしてみてください!
正規表現でチェックを行う4つのパターン
ここからは、正規表現を使うための基本となる特殊文字を、4つのパターンに分けて解説致します。また、覚える特殊文字は全部合わせても12個しかないので、1つずつ意味を理解しながらこの機会に全部覚えてしまいましょう!
そうすれば、冒頭で例に出した郵便番号のパターンくらいなら、自分で考えて作ることは誰にでも出来るようになりますよ!
【. \w \d \s】特別な意味を表す文字パターン
ここで解説する特殊文字は、「.」「\w」「\d」「\s」の4つになります。
それぞれの意味は次のとおり!
- 「.」何らかの1文字
- 「\w」大文字小文字を含む英数字とアンダースコア
- 「\d」0〜9の数字
- 「\s」タブ、改行、スペース
例えば、サンプルとして「user01」〜「user99」までの文字をマッチさせるパターンを作ってみましょう!
/user\d\d/
このように書けばOKですね。「user」は固定で良いのでそのまま書き、「\d」は数字1文字を表すので2つ記述すると「00」〜「99」まで対応することが出来るわけです。
次に、「Hello Mike」「Hello Jane」の両方にマッチするパターンを作ってみましょう!
/Hello\s\w\w\w\w/
こちらも、「\w」が英数字1文字を表すので4つ記述することで、4文字の英語に対応できますね。ポイントは、「Hello」のあとに空白のスペースがあるので、それを意味する「\s」を明示的に書くという点でしょう。
それでは、「Hello 佐藤さん」「Hello 田中さん」の両方にマッチするパターンはどうでしょうか?
/Hello\s..さん/
このように書けばOK!
「\w」は英数字だけを表すので、日本語にはマッチしません。そのため、何らかの1文字を表す「.」を使うことで日本語名でもマッチするようにしているわけです。
【* + ? {}】繰り返しを表すパターン
ここで解説する特殊文字は、「*」「+」「?」「{}」の4つになります。
それぞれの意味は次のとおり!
- 「*」0文字以上の繰り返し
- 「+」1文字以上の繰り返し
- 「?」1文字が「ある」か「ない」か
- 「{}」繰り返す回数を指定
サンプル例として、例えば桁数の決まっていない数字をマッチさせたい場合を考えてみましょう!まずは、適当な数字「195」をマッチさせるパターンを作ります。
/\d\d\d/
数字1文字を表す「\d」を3つ記述すれば良いですよね。しかしながら、この数字の桁数がさまざまに変化する場合はどうでしょうか?例えば、「39384」とか「949582」とか「12」などです。
現在のパターン「/\d\d\d/」だと、最初の3つ分の数字しか適合しないので、「39384」の場合は「393」だけを検出し、「12」だと数字が3つ分ないので「null」になってしまいます。
このように、桁数や文字数が不明の場合に役立つのが「*」と「+」です。
今回のように数字であれば、「\d」を1つ記述してその後に続けて「*」「+」を書くだけでどんな桁数の数字にもマッチすることになります!
//「*」を使った繰り返しパターン /\d*/ //「+」を使った繰り返しパターン /\d+/
非常にシンプルになりましたね!
「*」と「+」の使い分けですが、例えば数字がまったく入力されなかった場合を考えてみましょう。
// 数字が入力されていない状態 const reg = ''; // 「*」の場合 const result = reg.match(/\d*/); // 「+」の場合 const result = reg.match(/\d+/);
「*」の場合は「空文字」がresultに返されるのに対して、「+」の場合は「null」が返り値としてresultに返されます。
つまり、1文字以上存在しないと検出できないのが「+」の特徴になっているわけです。
(この特徴を利用すると、ユーザーの未入力状態なども検出できますね…)
「{}」を使ったパターン
それでは、「{}」を使ったパターン例も見ていきましょう!「*」「+」は無制限に文字を繰り返していくのに対して、「{}」は繰り返し回数を指定できるのが最大の特徴です。
例えば、「user08 user192 user2457」という文字列の中から、「user192」だけを抽出するパターンを作ってみましょう。
「user」はそのまま固定で、その後に続く数字「192」が3桁の数字なので「{3}」と記述すればOKです!
/user\d{3}/
このように書くと、見事に「user192」だけが抽出できるのが分かります!
ちなみに、「{2, 6}」のように書くと「2〜6桁」の意味になり、特定の範囲を指定することも可能です。
「?」を使ったパターン
次に、「?」を使ったパターン例を見てみましょう!
例として、「1 time」〜「9 times」をマッチさせるパターンを作りたいのですが、注意点として末尾に複数形の「s」が付く場合と付かない場合があります。
このように、任意の文字が「存在するケース」と「存在しないケース」がある場合に役立つのが「?」です。
/\d\stimes?/
「time」はそのまま固定で、末尾の「s」に続けて「?」を付けることで、「s」の「ある」「なし」を表すことが出来るのです!
【^ $】文字の位置を表すパターン
ここで解説する特殊文字は、「^」「$」の2つになります。
それぞれの意味は次のとおり!
- 「^」行の先頭
- 「$」行の末尾
サンプルとして、まずは「user1」〜「user9」にマッチするパターンを作ってみます。
/user\d/
このように書けば良いですよね。
ところが、入力を間違って「myuser1」とした場合はどうなるでしょうか?現在のパターンだと、実は「my」という部分を除外すれば「user1」になるので、マッチすることになります。
しかし、想定していない文字が入力された場合、エラーにしたい場合もあるでしょう。このような時は「^」を使ってみましょう!
/^user\d/
「user」の前に「^」を付けました。
このように書くと、先頭が「user」で始まる文字のみ抽出することになります。なので、「myuser1」だとエラーになり、「user1」であれば検出できるというわけです。
「$」も使い方は同じです!
/user\d$/
このように書くと、「user1abc」はエラーになりますが、「user1」は検出できるようになります。
ちなみに、「^」〜「$」でパターンを囲めば、前後に余計な文字があるとエラーになるので、さらに検出精度がアップするでしょう。
/^user\d$/
【[] ()】任意の文字列を表すパターン
ここで解説する特殊文字は、「[ ]」「( )」2つになります。
それぞれの意味は次のとおり!
- 「[ ]」一連の文字セットを表す
- 「( )」文字パターンをグループ化する
サンプル例として、HTMLの「<a>」「<p>」どちらかにマッチするパターンを作ってみましょう!先に正解を書くとこうなります!
/<[ap]>/
「[ ]」の中に「[ap]」のように書くと、「a」か「p」のいずれかの1文字を検出できるようになります。そのため、「<[ap]>」と記述すれば、「<a>」「<p>」のどちらかにマッチするパターンになるというわけです。
「[ ]」はいくつか活用方法があり、例えば「-」を使って「[A-Za-z]」と書くと大文字「A〜Z」か小文字「a〜z」のいずれか1文字を検出できる意味になります。
次に、「<a>」「<p>」だけでなく「<div>」にもマッチするパターンを作ってみましょう!
この場合、「[apdiv]」と書いてしまうと「a, p, d, i, v」それぞれの1文字いずれかを検出するという意味になってしまいます。そこで、「( )」を使いましょう。
/<(a|p|div)>/
このように「|」を使うと文字列を分けることが可能で、この場合だと「a」「p」「div」のいずれかを検出することになります。
「[ ]」と「( )」は、正規表現でもよく使われる特殊文字なので、さまざまな文字列でぜひ試してみてください!
ちなみに、JavaScriptによる正規表現を気軽に試せるWebサービス「RegExr」を使うと、学習効果がさらに上がるのでぜひ参考にしてみてください!
正規表現のエスケープについて
この章では、正規表現におけるエスケープの方法について見ていきましょう!
エスケープが必要な場合について、またバックスラッシュを利用した手法について学んでいきます。
エスケープ処理が必要なケースとは?
正規表現で扱う「特殊文字(. * + ^ | [ ] ( ) ? $ { }など)」は、パターンを作成する時にエスケープしなければいけないケースがあります。
例えば、WebサイトのURLを例に見てみましょう!
const url = 'www.sejuku.net'; const regexp = new RegExp(/www.sejuku.net/); const result = regexp.test(url); console.log(result);
実行結果
true
この例では、「test()」メソッドを使って正規表現とURLが一致するかを確認しています。
実行結果を見ると「true」になっているので一致しているのが分かりますね。つまり、この正規表現は指定したURLをしっかりと検出してくれるというわけです。
そこで、試しに文字列「.(ドット)」の部分をアルファベットの「z」に置換して同じ処理を実行してみましょう!
//「.(ドット)」を「z」に置き換える const url = 'wwwzsejukuznet'; const regexp = new RegExp(/www.sejuku.net/); const result = regexp.test(url); console.log(result);
実行結果
true
正規表現のパターンと明らかに異なるので、これは検出しないように感じますよね?
しかしながら、実行結果を見ると「true」になっています!実はこの場合でも正規表現パターンは指定したURLを検出できるのです!
理由は簡単で、正規表現の世界で「.(ドット)」はどんな文字でも検出するというルールがあるからなのです。つまり、文字列のURLで記述した「.(ドット)」と正規表現パターンで記述した「.(ドット)」は似て非なるものというわけです!
このような状況の場合に必要となるのが「エスケープ」処理なのです。
バックスラッシュを使ったエスケープ方法
正規表現でエスケープ処理を行うのに必要なのは「 (バックスラッシュ)」です
そこで、先ほど正規表現パターンに記述していた「.(ドット)」をエスケープして同じ処理を実行してみましょう!
const url = 'wwwzsejukuznet'; //「.」をエスケープする const regexp = new RegExp(/www\.sejuku\.net/); const result = regexp.test(url); console.log(result);
実行結果
false
注目すべきは正規表現パターンの「.(ドット)」の箇所です!「\.」のように「.(ドット)」の前に「(バックスラッシュ)」を記述することで、通常の文字「.(ドット)」を意味することになります。
そのため、「z」に置換されている文字列は正規表現パターンと異なるので実行結果は「false」となるわけです。
ちなみに、JavaScriptにおけるエスケープ処理の基本から活用事例については、次の記事で詳しく解説していますのでぜひ参考にしてみてください!
正規表現のメソッド
次に正規表現を実際のプログラミングで使うことが多い、主なメソッドを5種類ご紹介します。
これらのメソッドを活用することで、正規表現パターンをより柔軟に効率よく活用することができるのでぜひ参考にしてみてください!
matchメソッドによる文字列検索を行う方法
正規表現を使ったケースでよく使われるメソッドとして「match()」があります。「match()」はそもそもStringオブジェクトの組み込みメソッドとして用意されており、文字列を検索するのに優れた機能を持っています。
さらに、正規表現パターンも柔軟に利用できるメソッドであることから、特殊な文字列を検索する際によく使われます。
「match()」を使った正規表現パターンの記述方法は、【 文字列.match( 正規表現パターン ) 】のように引数へ指定すればOKです。
次のサンプル例を見てください!
const users = 'user, user1, user-2, myuser'; const regexp = new RegExp(/user-\d/); const result = users.match( regexp ); console.log( result[0] );
実行結果
user-2
この例では、さまざまな形式で記述されたユーザー名の文字列を用意しています。RegExp()を使って正規表現パターンを「/user-\d/」のように指定しているのが分かりますね。
「users.match( regexp )」のように記述することで、「user-」から始まる数字の文字列パターンを検出しているわけです。このパターンに該当するのは「user-2」だけしかないのが、実行結果からも分かりますね。
他にも、「match()」についての基本から活用事例までを次の記事で詳しくまとめているので、ぜひ参考にしてみてください!
searchメソッドによる文字の位置を検索する方法
今度は「search()」メソッドについて見ていきましょう!「search()」は、対象文字列の中に目的のキーワードが何文字目に存在するかをチェックすることができます。
記述方法としては、【 対象文字列.search( 目的のキーワードか正規表現 ) 】のように引数に正規表現パターンを指定できます。
次のサンプル例を見てください!
const str = 'user-12, user-Mike, user-325, user-Jane'; const result = str.search( /user-\d{3}/ ); console.log( result );
実行結果
20
この例では、数人分のユーザー名を記述した文字列を変数「str」に格納しています。正規表現パターンとしては、「/user-\d{3}/」と記述することでuser-から始まる3桁の数字を持つユーザー名を検出するようにしています。
そこで、用意した文字列に対して「search( /user-\d{3}/ )」と記述すれば「user-325」だけが検出できるわけです。
文字列の先頭(0)から20文字目に「user-325」が存在しているので、実行結果は20になるという意味になります。
ちなみに、JavaScriptによる文字列の検索術やsearch()を使った更なる活用事例を次の記事でまとめているので参考にしてみてください!
testメソッドによるtrue / falseの取得方法
「test()」は、正規表現パターンに合致するかどうかを手軽に「true / false」でチェクすることが可能です。
記述方法としては、【 正規表現パターン.test( 対象の文字列・数値 ) 】のように引数へ対象の値を指定します。例えば、数値をチェックする例を見てましょう!
const regexp = new RegExp(/^\d{2}$/); const result1 = regexp.test( 8 ); const result2 = regexp.test( 45 ); const result3 = regexp.test( 768 ); console.log( '8 = ^d{2}$は' + result1 ); console.log( '45 = ^d{2}$は' + result2 ); console.log( '768 = ^d{2}$は' + result3 );
実行結果
8 = ^d{2}$はfalse 45 = ^d{2}$はtrue 768 = ^d{2}$はfalse
この例では、1桁・2桁・3桁の数値を対象に正規表現パターンを作成しています。正規表現パターンは、「/^\d{2}$/」のように2桁の数値だけを検出するように指定しているのがポイントです。
そして、「8」「45」「768」のそれぞれの数値をtest()を使ってチェックしているわけです。結果的には、2桁の数値である「45」だけがtrueとなっているのが実行結果から分かりますね。
このように、true / falseだけを取得して条件分岐などを作りたい場合にtest()メソッドは有効な手段となるわけです。
正規表現における文字列操作
この章では、主に文字列操作を基本とする正規表現の使い方について見ていきましょう!
一般的によく使われるreplace(置換)、split(分割)についてのメソッドを学んでいきます。
replaceメソッドで正規表現を使った文字列置換
「replaceメソッド」は、任意の文字列と置換したい文字列を指定することで置換処理を行えるメソッドです。
使い方は簡単で【 対象文字列.replace( 正規表現パターン, 置換する文字列 ) 】のように引数を設定するだけです。具体的なサンプルで確認をしてみましょう!
例えば、電話番号の数値をすべて「*」に置換したい場合は次のように記述します。
const tel_data = "090-1234-5678"; const result = tel_data.replace(/^\d{3}-\d{4}-\d{4}$/, '***-****-****'); console.log(result);
電話番号は「3桁+4桁+4桁」の数字がハイフンで繋がっている文字列パターンですよね?
このパターンを利用して正規表現を使い「*」に置換するというわけです。このようにreplaceメソッドは正規表現と相性が良く、よく利用されるので覚えておきましょう!
splitメソッドによる文字列を分割する方法
splitメソッドで正規表現を使って分割する方法を解説します。splitメソッドは引数に文字列以外にも正規表現で指定することができます。
次のプログラムで確認してみましょう。
const str = 'user-1,user-2 user-3'; //「,(カンマ)」「空白」を区切り文字に使う const result = str.split(/,|\s/); console.log( result );
実行結果:
["user-1", "user-2", "user-3"]
この例では、対象となる文字列が「user-1,user-2」のように「,(カンマ)」で区切られていたり、「user-2 user-3」のように「空白」で区切られています。
このような場合は正規表現を使うと非常に簡単で、「/,|\s/」と記述すれば「,(カンマ)」「空白」の両方を区切り文字とし使え、出力結果のようにきれいな配列データになるわけです。
splitメソッドの詳しい使い方はこちらの記事で解説しているので、ぜひ確認してください。
正規表現の実践例
この章では、これまで学習してきた正規表現を使った事例をいくつかご紹介していきます!
主に、数字チェック・半角の英数字チェック・メールアドレスチェックについて学んでいきます。
正規表現で任意の数字をチェックする
まずは、正規表現を使って任意の「数字パターン」を検証する方法について見ていきましょう!
最初に基本となる数字パターンを正規表現で記述してみます。
const regexp = /^[0-9]*$/; const result = regexp.test(123);
この例では、正規表現パターンとして「^[0-9]*$」を設定しています。
[0-9]で0〜9までの数字を意味しており、*を付与することで複数の桁数を許容しています。あとは、^ $を付与することで数字パターンだけを検証できますね。
応用として、マイナスの数字を検証できるようにするには次の通りです!
const regexp = /^[-]?[0-9]*$/; const result = regexp.test(-123);
先ほどの数字パターンの先頭へ[-]?を付与しているのが分かるでしょうか?これにより、マイナス(-)の有無による数字を検証できるようになるわけです。
さらに、小数点についても同じように検証するにはどうすればいいでしょうか?考え方は同じで、小数点の「.(ドット)」を含めた数字の有無を検証できるようにすればいいわけです。
const regexp = /^[-]?[0-9]*(.[0-9]*)?$/; const result = regexp.test(123.45);
これまでの数字パターンに(.[0-9]?)を追加しています。
「.(ドット)」以降の数字パターンを含めて( )で囲むことで、小数点の有無を表現しているわけですね。
正規表現で半角の英数字をチェックする
次に、入力フォームなどでよく使う半角の英数字の検証について見ていきましょう!
数字だけでなく半角の英字も含めたパターンは次のように表現できます。
const regexp = /^[0-9a-zA-Z]*$/; const result = regexp.test('123abcABC');
[0-9]だけでなく、[a-z]や「A-Z」も含めることですべてのアルファベットを含めた英数字を検証することができます。
このパターンをベースにして、例えば入力フォームなどで「3文字以上8文字以内」のようにルールを追加したい場合は次のようになります。
const regexp = /^[0-9a-zA-Z]{3,8}$/; const result = regexp.test('12abAB');
英数字パターンに{3, 8}を追加していますね。
これにより、3文字以上8文字以内の英数字だけを許容するという意味になるわけです。
まとめ
今回は、基本的な正規表現のパターンを学習しました!
学んだ内容のポイントを、もう一度振り返ってみましょう。
- 直接パターンを指定する方法と、RegExpオブジェクトを作る方法がある
- 特殊文字の組み合わせで「パターン」を作って文字を検出できる
- 12個の特殊文字を組み合わせることで、さまざまなパターンが作れる
- メソッドを活用することで正規表現をより効率よく活用できる
これらの内容を踏まえながら、自分なりの正規表現パターンを作成できるように頑張っていきましょう!