こんにちは、かつコーチです。
前回はDateオブジェクトで日付・時刻を扱う方法を解説しました。
今回は、文字列のパターンマッチングに使う「正規表現」の基本を扱います。
正規表現は最初は記号だらけで難しく見えますが、フォームのバリデーション(入力チェック)や文字列の抽出・置換など、実務で本当によく使う道具です。
苦手意識を持っている人も多いテーマなので、できるだけかみ砕いて解説していきます。
正規表現とは?
文字列の「パターン」を表す特別な記法
正規表現とは、文字列の中から特定の「パターン」を探し出すためのルールを記述する記法です。
「メールアドレスの形式になっているか」「数字だけで構成されているか」といった、文字列の“形”をチェックしたいときに威力を発揮します。
JavaScriptでは、正規表現を /パターン/フラグ という形式(リテラル記法)、または new RegExp() で作成します。
// リテラル記法(よく使われる書き方)
const pattern1 = /abc/;
// RegExpコンストラクタを使う書き方(動的にパターンを組み立てたいときに使う)
const pattern2 = new RegExp("abc");
普段はリテラル記法を使い、変数からパターンを組み立てたい場合だけ RegExp を使う、というのが一般的な使い分けです。
なぜ正規表現が必要なのか
正規表現を使わずに文字列をチェックしようとすると、条件分岐だらけの読みにくいコードになりがちです。
❌ Before:正規表現を使わずに愚直にチェックする
// 郵便番号(123-4567形式)かどうかをチェックする(正規表現なし)
function isPostalCode(str) {
if (str.length !== 8) return false;
if (str[3] !== "-") return false;
for (let i = 0; i < str.length; i++) {
if (i === 3) continue;
if (str[i] < "0" || str[i] > "9") return false;
}
return true;
}
console.log(isPostalCode("123-4567")); // true
チェック内容は単純なのに、コードはかなり長くなってしまいます。
✅ After:正規表現で1行のパターンとして表現する
// 郵便番号(123-4567形式)かどうかをチェックする(正規表現あり)
function isPostalCode(str) {
const pattern = /^\d{3}-\d{4}$/;
return pattern.test(str);
}
console.log(isPostalCode("123-4567")); // true
console.log(isPostalCode("1234567")); // false(ハイフンがない)
「3桁の数字、ハイフン、4桁の数字」という条件が、/^\d{3}-\d{4}$/ という短いパターンだけで表現できています。
この“表現力の高さ”こそが、正規表現を学ぶ最大のメリットです。
基本の書き方
よく使う記号一覧
まずは最低限覚えておきたい記号を整理しておきます。
| 記号 | 意味 | 例 |
|---|---|---|
\d | 数字1文字 | \d\d は「数字2文字」 |
\w | 英数字・アンダースコア1文字 | \w+ は「英数字が1文字以上」 |
\s | 空白文字(半角スペース・タブなど) | |
. | 任意の1文字 | |
* | 直前の文字が0回以上 | ab* は a, ab, abb にマッチ |
+ | 直前の文字が1回以上 | ab+ は ab, abb にマッチ(a は不可) |
? | 直前の文字が0回または1回 | |
{n,m} | 直前の文字がn回以上m回以下 | \d{3,4} は数字3〜4桁 |
^ | 文字列の先頭 | |
$ | 文字列の末尾 | |
[] | いずれかの文字(文字クラス) | [aiueo] は母音のいずれか1文字 |
マッチするかを調べる:test
文字列がパターンに一致するかどうかは test メソッドで調べます。
const pattern = /^[a-zA-Z0-9_]+$/; // 英数字とアンダースコアのみ
console.log(pattern.test("katsu_coach01")); // true
console.log(pattern.test("かつコーチ")); // false(日本語は含まれていない)
^ と $ で文字列全体を囲むことで、「部分的に一致する」のではなく「文字列全体がこのパターンに完全一致するか」をチェックできます。
私はこの ^ $ を書き忘れて、「1文字でも条件を満たす部分があればtrueになってしまう」というバグを出したことがあります。
❌ Before:^ $ を付け忘れる
const pattern = /\d{3}/; // 「数字3桁を含むか」というパターンになってしまう
console.log(pattern.test("abc123def")); // true(意図せず一致してしまう)
「郵便番号かどうか」をチェックしたいつもりが、これでは「数字3桁がどこかに含まれているか」という判定になってしまい、"abc123def" のような文字列にも一致してしまいます。
✅ After:^ $ で完全一致にする
const pattern = /^\d{3}$/; // 「文字列全体が数字3桁である」というパターン
console.log(pattern.test("abc123def")); // false
console.log(pattern.test("123")); // true
「一部が一致すればいいのか、全体が一致すべきなのか」を意識するだけで、この手の事故は防げます。
マッチした文字列を取り出す:match
パターンに一致した部分の文字列そのものを取り出したい場合は match を使います。
const text = "お問い合わせ先: 03-1234-5678 です";
const pattern = /\d{2,4}-\d{2,4}-\d{4}/;
const result = text.match(pattern);
console.log(result[0]); // "03-1234-5678"
置換する:replace
文字列の一部をパターンで検索して置き換える場合は replace を使います。
const text = "価格は1000円、送料は300円です";
// gフラグを付けると、最初の1件だけでなく全ての一致箇所を置換する
const result = text.replace(/\d+円/g, "***円");
console.log(result); // "価格は***円、送料は***円です"
g(グローバル)フラグを付けないと最初の1件しか置換されないので、複数箇所を一括で置換したいときは忘れずに付けましょう。
実践:よく使うパターン集
メールアドレスのチェック
function isEmail(str) {
const pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return pattern.test(str);
}
console.log(isEmail("info@katsu-coach.com")); // true
console.log(isEmail("info@katsu-coach")); // false(ドメインの末尾がない)
なお、実務上は「厳密なメール形式のチェックは正規表現だけでは完璧にできない」とも言われているため、最終的な確認は確認メール送信などと組み合わせるのが実践的です。
半角数字のみの入力チェック
function isNumericOnly(str) {
return /^\d+$/.test(str);
}
console.log(isNumericOnly("12345")); // true
console.log(isNumericOnly("123a5")); // false
全角文字を半角に置換する下準備(カタカナの抽出)
const text = "商品名:ノートPC、価格:98000円";
// カタカナだけを抽出する
const katakanaList = text.match(/[ァ-ヶー]+/g);
console.log(katakanaList); // ["ノート"]
[ァ-ヶー] のように、文字コードの範囲を - でつないで指定することで、「カタカナのいずれか」のような文字クラスを作れます。
グループ化とキャプチャ:一歩先の使い方
()で囲んでパターンの一部を取り出す
正規表現では () で囲んだ部分を「グループ」として個別に取り出せます。
const text = "2026-08-12";
const pattern = /^(\d{4})-(\d{2})-(\d{2})$/;
const result = text.match(pattern);
console.log(result[0]); // "2026-08-12"(マッチ全体)
console.log(result[1]); // "2026"(1つ目のグループ:年)
console.log(result[2]); // "08"(2つ目のグループ:月)
console.log(result[3]); // "12"(3つ目のグループ:日)
名前付きグループで可読性を上げる
グループが増えてくると、result[1] result[2] だけでは何を表しているか分かりにくくなります。
そんなときは、(?<名前>パターン) の形式で名前付きグループを使うと読みやすくなります。
const text = "2026-08-12";
const pattern = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/;
const result = text.match(pattern);
console.log(result.groups.year); // "2026"
console.log(result.groups.month); // "08"
console.log(result.groups.day); // "12"
result.groups.year のように名前でアクセスできるため、パターンが複雑になるほどこの書き方の恩恵が大きくなります。
まとめ
この記事のポイント
- 正規表現は文字列の「パターン」をチェック・抽出・置換するための記法
test(真偽判定)、match(抽出)、replace(置換)が基本の3メソッド^$を付け忘れると「部分一致」になり、意図しない結果を招きやすいgフラグを付けないと最初の1件しか置換されない()によるグループ化・名前付きグループで、複雑なパターンも読みやすく扱える
次に読むべき記事
次回は、一定時間後に処理を実行する「setTimeout」と、繰り返し処理を実行する「setInterval」の使い方を解説していきます。
→ 次の記事:setTimeout・setIntervalでタイマー処理を実装する