【JavaScript】JavaScriptの正規表現入門

javascript-icon JavaScript

こんにちは、かつコーチです。

前回は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でタイマー処理を実装する

タイトルとURLをコピーしました