正規表現とは何か
正規表現とは、文字列の中から特定のパターンを探したり、条件に一致する文字列かどうかを判定したりするための記述方法です。
単なる文字の一致だけでなく、文字の種類や並び方、位置や回数といった条件をまとめて表現できるため、入力チェックや検索、置換処理など幅広い場面で利用されます。
この記事では、正規表現の基本構造と、よく使われる代表的な記号を段階的に解説します。
正規表現の第一歩
正規表現は、文字列がある条件に合っているかを調べるための仕組みです。
JavaScriptでは、正規表現に対してtest()を使うことで、その判定を行います。
構文
/条件/.test(文字列);
この1行で文字列が条件に一致しているかを判定できます。
詳しく見ていきましょう。
まず、/条件/のスラッシュで囲まれた条件が正規表現です。
ここにどんな文字を許可するかという条件を書きます。
続くtest(文字列)は、正規表現と文字列を照合するための処理です。
イメージ図で見てみましょう。
正規表現・test()のイメージ図
記述は少し独特ですが、処理の流れ自体はシンプルです。
では、実際に何を照合するのか見ていきましょう。
文字クラス
文字クラスは、複数の文字の中からいずれか1文字に一致させたい場合に使用します。
構文
[条件]
ブラケット[]の中に指定した文字のうち、どれか1文字に一致します。
順番は関係なく、含まれているかどうかのみが判定基準になります。
コード例
//literals1.js
const value = 'cde';
if (/[abc]/.test(value)) {
alert("含まれています");
} else {
alert("含まれていません");
}
動作例
/[abc]/の正規表現は、aまたはbまたはcのいずれか1文字に一致します。
照合したい文字列はvalueに代入したcdeで、cが該当するためalertには含まれていますと表示されます。
次に文字の位置を指定する場合はどうすればいいでしょうか。
構文
^条件
条件$
まず最初の構文には条件の前に^がついています。
これは文字列の先頭を表しています。
次の構文には条件の後に$がついています。
これは文字列の末尾を表しています。
コード例
//literals2.js
const value = 'ade';
if (/^a/.test(value)) {
alert("aから始まります");
} else {
alert("aから始まりません");
}
if (/d$/.test(value)){
alert("dで終わっています");
} else {
alert("dで終わっていません");
}
動作例
/^a/の正規表現は、照合する文字列がaから始まっているかを判別します。
照合したい文字列はvalueに代入したadeで、aから始まっているため、alertにはaから始まりますと表示されます。
一方で/d$/の正規表現は、照合する文字列がdで終わっているかを判別します。
照合したい文字列の終わりはeなので、dで終わっていないため、alertにはdで終わっていませんと表示されます。
^と$を同時に使うとどうなるでしょうか。
コード例
//literals3.js
let value = 'abcd';
if (/^abcd$/.test(value)) {
alert("完全に一致しています");
} else {
alert("一致しません");
}
value = 'acbd';
if (/^abcd$/.test(value)) {
alert("完全に一致しています");
} else {
alert("一致しません");
}
動作例
まず、valueにabcdを代入して、最初のif文で^abcd$とvalueのabcdを照合します。
順番も文字もすべて同じため、alertで完全に一致していますと表示されます。
次にvalueにacbdを代入して、次のif文で同じように照合すると、先頭と末尾の文字は同じですが、順番が異なるため、alertで一致しませんと表示されます。
^は文字列の先頭、$は文字列の末尾を表すと説明しましたが、^と$で囲むことで、囲まれた内容が完全に一致しているかを判定する役割になります。
正規表現では、このように記号を組み合わせることで判定の意味が変わることがあります。
では、なぜ最初の構文では[]を使い、^や$では[]を使わなかったのでしょうか。
なお、[^条件]とすると否定という意味になりますが、意味が変わるため、後ほど説明します。
今は理解しなくてもかまいません。
理解しておくべきことは次の3つです。
[条件]は文字の集合を表し、その中のどれか1文字に一致するかを判定する
^文字や文字$は、文字そのものではなく、文字列の先頭や末尾といった位置を表す
^文字列$は、先頭と末尾の位置指定を組み合わせることで、文字列全体が完全に一致しているかを判定する
この3つだけ、しっかり理解しておきましょう。
任意の1文字
.は任意の1文字を表します。
英数字でも記号でも、何か1文字あれば一致します。
構文
/./
1文字以上あるかどうかを調べるときによく使われます。
コード例
//literals4.js
const value = 'a';
if (/./.test(value)) {
alert("1文字以上あります");
} else {
alert("空文字です");
}
動作例
valueにはaと文字が代入されているため、1文字以上ある状態です。
そのためalertには1文字以上ありますと表示されます。
では、空文字と比較してみましょう。
コード例
//literals5.js
const value = '';
if (/./.test(value)) {
alert("1文字以上あります");
} else {
alert("空文字です");
}
動作例
valueは空文字なので、1文字も存在しません。
そのため/./は一致せず、alertには空文字ですと表示されます。
[条件]と何が違うのでしょうか?
それは[]内のどれか1文字が含まれているか、.は種類を問わず何か1文字が含まれているかの違いで、つまり.は条件を指定しない[]のようなものと考えてください。
ただし、厳密には改行は含まれない点が異なります。
では、1文字ではなく、2文字以上あるかを判定したい場合はどうすればいいでしょうか。
量指定子
量指定子とは繰り返しを意味します。
正規表現では、直前の文字や条件に対して何回繰り返すかを指定できます。
なお、繰り返しはいくつか存在しますが、よく使うもののみ説明します。
構文
条件+
条件*
条件?
+は直前に書かれた文字や文字クラスが、最低1回以上連続して出現する場合に一致します。
*は直前の条件が0回以上繰り返されることを表します。
?は直前の条件が0回または1回だけ出現することを表します。
コード例
//literals6.js
const value = 'abc';
if (/.+/.test(value)) {
alert("1文字以上あります");
} else {
alert("空文字です");
}
動作例
+を使っていますが分解して説明します。
まず.は任意の1文字で、+は1回以上という意味です。
.+は任意の文字が1文字以上あるか判定します。
valueはabcで3文字あるため一致するため、alertには1文字以上ありますと表示されます。
コード例
//literals7.js
const value = '';
if (/.*/.test(value)) {
alert("常に一致します");
}
動作例
*を使っていますが分解して説明します。
まず.は任意の1文字で、*は0回以上という意味です。
.*は任意の文字がなくてもよいと判定します。
そのため、valueが空文字でも、alertには常に一致しますと表示されます。
ただし、入力チェックには向かない場合があります。
コード例
//literals8.js
const value = 'a';
const empty = '';
if (/a?/.test(value)) {
alert("一致します");
}
if (/a?/.test(empty)) {
alert("一致します");
}
動作例
?は0回または1回という意味なので、alertはaがあってもなくても一致します。
実際、valueはaが入ってるため、emptyは空文字でも一致します。
存在してもしなくてもいい文字を表すときに使います。
では、これらはどうやって使えばいいのか?
まず、条件を設計しながら設定します。
先頭に#があってもなくてもよい→#?
その後にgから始まる1文字以上の文字が続く→#?g.+
末尾に!が 0文字以上ついてもよい→#?g.+!
文字列全体を判定する→/^#?g.+!$/
以上の条件を設定したコード例を見てみましょう。
コード例
//literals9.js
const value = ['#good morning!!', '#hello!!', 'good evening!', '#good night'];
for (let i = 0; i < value.length; i++) {
if (/^#?g.+!*$/.test(value[i])) {
alert("条件に一致しています");
} else {
alert("条件に一致していません");
}
}
動作例
まず、#good morning!!は、先頭に#があってもよく、gで始まり、その後に文字が続き、末尾に!があってもよいので、条件に一致します。
次に、#hello!!先頭に#はありますが、gで始まっていないため条件に一致しません。
続いて、good evening!は先頭に#はなくてもよく、gで始まり、その後に文字が続き、末尾に!があってもよいので、条件に一致します。
最後に、#good nightは先頭に#があってもよく、gで始まり、その後に文字が続き、末尾に!はなくてもいいので、条件に一致します。
このように、正規表現の各部分がどの文字列に当てはまるかを順に見ていくと、どの文字列が一致するかを直感的に理解できます。
また、正規表現は左から右へと評価されるため、#hello!!はgから始まっていない時点で、それより後の条件は評価されず不一致となります。
半角・全角文字
日本語には半角文字・全角文字という概念があります。
日頃会員登録やアンケートの場面で全角文字で入力してください、半角数字で入力してくださいという場面に遭遇すると思います。
正規表現では半角・全角文字のチェックも可能です。
構文
[0-9]
[0-9]
[A-Za-z]
[A-Za-z]
[ぁ-ん]
[ァ-ヶ]
[ヲ-゚]
[0-9]は半角数字、[0-9]は全角数字、[A-Za-z]は半角英字、[A-Za-z]は全角英字で、入力チェックでも最も使用頻度が高い文字種です。
[ぁ-ん]は平仮名、[ァ-ヶ]は全角カタカナ、[ヲ-゚]は半角カタカナで、英数に次ぎ使用頻度が高い文字種です。
文字クラスを使うことで、許可したい文字種をまとめて指定でき、英数に関しては順番通りでよいため覚えやすいと思います。
一方で平仮名、全角カタカナ、半角カタカナは文字の配置を基に指定するため、この形を覚えなくてはなりません。
コード例
//literals10.js
let value = prompt('文字を入力してください');
if (/^[0-9]$/.test(value)) {
alert("半角数字です");
} else if (/^[A-Za-z]$/.test(value)) {
alert("半角英字です");
} else {
alert('半角英数以外です');
}
動作例
このコード例ではpromptに入力した文字を正規表現で判別しています。
最初に、^[0-9]$で文字列すべてが半角数字かどうか判別し、半角数字のみだとalertに半角数字ですと表示されます。
次に、半角数字ではなかったら半角英字かどうか判別し、半角英字のみだとalertに半角英字ですと表示されます。
最後に半角数字でも半角英字でもなかったら、半角英数以外ですと表示されます。
このように入力した文字列が、大きくルールに則っているかの判別も可能です。
ひらがなやカタカナも同じように指定できます。
しかし、長音(ー)に関しては別途、許可する文字を追加する必要がありますが、今理解する必要がないためフォームで解説します。
中括弧量指定子
中括弧量指定子{}は、直前の条件が出現する回数を数値で指定するための記号です。
構文
条件{回数}
条件{最小, 最大}
条件{最小,}
{}の中に数値を書くことで、直前の文字や文字クラスの繰り返し回数を指定します。
1つの数値のみ指定した場合は、その回数ちょうどに一致します。
カンマを使うことで、回数の範囲指定や下限のみの指定も可能です。
コード例
//literals11.js
let zip = "123-4567";
if (/^[0-9]{3}-[0-9]{4}$/.test(zip)) {
console.log(zip + " は正しい郵便番号です");
} else {
console.log(zip + " は正しい郵便番号ではありません");
}
let phone = "09012345678";
if (/^[0-9]{10,11}$/.test(phone)) {
console.log(phone + " は正しい電話番号です");
} else {
console.log(phone + " は正しい電話番号ではありません");
}
let password = "P@ssw0rd!";
if (/^[A-Za-z0-9!@#$%^&*]{8,}$/.test(password)) {
console.log(password + " は有効なパスワードです");
} else {
console.log(password + " は有効なパスワードではありません");
}
動作例
まず、郵便番号は3桁とハイフンと4桁の並びで構成されています。
そのため、^[0-9]{3}-[0-9]{4}$で正規表現が使用でき、一致させることができます。
続いて、電話番号はハイフンなしで10桁か11桁で構成されています。
そのため、^[0-9]{10,11}$で正規表現が使用でき、一致させることができます。
最後にパスワードは8文字以上で設定という条件の基で構成しました。
そのため、^[A-Za-z0-9!@#$%^&*]{8,}で正規表現が使用でき、一致させることができます。
このように入力チェックでは{}を使用して正規表現を使うことができます。
ただ、すべて覚えておくのは至難の業なので、よく使う正規表現を使いまわせるようフォーマット化しておけば、実際に使用する際にコピー&ペーストできるよう準備をしておくとよいでしょう。