はじめに

Webアプリケーション開発では、ユーザー入力のバリデーション、テキストの検索・置換、ログ解析など、文字列を柔軟に操作する場面が数多くあります。このような処理を効率的に行うために欠かせないのが「正規表現(Regular Expression)」です。

正規表現を使えば、「メールアドレスの形式かどうか」「電話番号のパターンに一致するか」「特定の文字列を別の文字列に置き換える」といった複雑な文字列処理を、簡潔なコードで実現できます。

本記事では、以下の内容を初心者向けにわかりやすく解説します。

  • 正規表現とは何か
  • RegExpオブジェクトの作成方法
  • パターンの基本構文
  • フラグの種類と使い方
  • 文字列のマッチ(検索)
  • 文字列の置換
  • 文字列の分割
  • マッチした部分の抽出
  • 実践的な活用例

正規表現とは

正規表現とは、文字列のパターンを表現するための特殊な記法です。英語では「Regular Expression」と呼ばれ、略して「regex」や「regexp」と表記されます。

正規表現を使うと、単純な文字列比較ではできない柔軟なマッチングが可能になります。

1
2
3
4
5
6
7
// 通常の文字列比較
const text = "私の電話番号は090-1234-5678です";
console.log(text.includes("090-1234-5678")); // true(完全一致のみ)

// 正規表現を使ったパターンマッチング
const phonePattern = /\d{3}-\d{4}-\d{4}/;
console.log(phonePattern.test(text)); // true(パターンに一致)

上記の例では、正規表現を使うことで「3桁-4桁-4桁の数字パターン」に一致するかどうかを判定しています。電話番号が「080-9999-0000」でも「070-5555-1234」でも、同じパターンでマッチできます。

RegExpオブジェクトの作成方法

JavaScriptで正規表現を使うには、RegExp オブジェクトを作成します。作成方法は主に2つあります。

正規表現リテラルで作成する(推奨)

スラッシュ / で囲んでパターンを記述する方法です。最も一般的で、コードが読みやすくなります。

1
2
3
4
5
// 正規表現リテラル
const pattern = /hello/;

// フラグ付きの正規表現
const patternWithFlag = /hello/i; // 大文字小文字を区別しない

RegExpコンストラクタで作成する

new RegExp() を使って作成する方法です。パターンを動的に生成したい場合に便利です。

1
2
3
4
5
6
7
8
9
// RegExpコンストラクタ
const pattern = new RegExp("hello");

// フラグ付き
const patternWithFlag = new RegExp("hello", "i");

// 変数を使ってパターンを動的に生成
const searchWord = "JavaScript";
const dynamicPattern = new RegExp(searchWord, "gi");

コンストラクタを使う場合、バックスラッシュ \ はエスケープが必要なため、特殊文字を使うときは注意が必要です。

1
2
3
// 数字にマッチするパターン
const regexLiteral = /\d+/;             // リテラル
const regexConstructor = new RegExp("\\d+"); // コンストラクタ(エスケープ必要)

正規表現の作成方法の使い分け

方法 用途 注意点
リテラル /pattern/ パターンが固定の場合 スラッシュをエスケープする必要がある
コンストラクタ new RegExp() パターンを動的に生成する場合 バックスラッシュのエスケープが必要

パターンの基本構文

正規表現のパターンは、通常の文字と「メタ文字」と呼ばれる特殊な意味を持つ文字で構成されます。

基本的なメタ文字

メタ文字 意味
. 任意の1文字(改行を除く) /a.c/ は “abc”, “aXc” などにマッチ
^ 文字列の先頭 /^Hello/ は先頭の “Hello” にマッチ
$ 文字列の末尾 /world$/ は末尾の “world” にマッチ
\ 次の文字をエスケープ /\./ は文字としての “.” にマッチ
1
2
3
4
5
const text = "Hello, World!";

console.log(/^Hello/.test(text));  // true(先頭が Hello)
console.log(/World!$/.test(text)); // true(末尾が World!)
console.log(/o.W/.test(text));     // true(o と W の間に任意の1文字)

文字クラス

特定の文字グループにマッチさせるための記法です。

記法 意味
[abc] a, b, c のいずれか1文字 /[aeiou]/ は母音にマッチ
[^abc] a, b, c 以外の1文字 /[^0-9]/ は数字以外にマッチ
[a-z] a から z までの1文字 /[A-Za-z]/ はアルファベットにマッチ
\d 数字([0-9] と同じ) /\d{3}/ は3桁の数字にマッチ
\D 数字以外 /\D+/ は数字以外の連続にマッチ
\w 英数字とアンダースコア([A-Za-z0-9_] /\w+/ は単語にマッチ
\W \w 以外の文字 /\W/ は記号や空白にマッチ
\s 空白文字(スペース、タブ、改行など) /\s+/ は空白の連続にマッチ
\S 空白以外の文字 /\S+/ は空白以外の連続にマッチ
1
2
3
4
5
const text = "電話: 03-1234-5678";

console.log(/\d/.test(text));    // true(数字が含まれている)
console.log(/[0-9-]+/.test(text)); // true(数字とハイフンのパターン)
console.log(/\w+/.test(text));   // true(英数字が含まれている)

量指定子

文字やパターンの繰り返し回数を指定します。

記法 意味
* 0回以上 /ab*c/ は “ac”, “abc”, “abbc” などにマッチ
+ 1回以上 /ab+c/ は “abc”, “abbc” などにマッチ(“ac” は不可)
? 0回または1回 /colou?r/ は “color”, “colour” にマッチ
{n} ちょうど n 回 /\d{4}/ は4桁の数字にマッチ
{n,} n 回以上 /\d{2,}/ は2桁以上の数字にマッチ
{n,m} n 回以上 m 回以下 /\d{2,4}/ は2〜4桁の数字にマッチ
1
2
3
4
5
6
7
8
9
// 郵便番号のパターン(3桁-4桁)
const postalCode = /^\d{3}-\d{4}$/;
console.log(postalCode.test("123-4567")); // true
console.log(postalCode.test("12-4567"));  // false(3桁ではない)

// 電話番号のパターン(ハイフンは省略可能)
const phone = /^\d{2,4}-?\d{2,4}-?\d{4}$/;
console.log(phone.test("03-1234-5678")); // true
console.log(phone.test("0312345678"));   // true

グループ化と選択

パターンをグループ化したり、複数のパターンから選択したりできます。

記法 意味
(pattern) グループ化(キャプチャ) /(ab)+/ は “ab”, “abab” などにマッチ
(?:pattern) グループ化(非キャプチャ) /(?:ab)+/ はグループ化するが結果に含まない
| 選択(OR) /cat|dog/ は “cat” または “dog” にマッチ
1
2
3
4
5
6
7
8
9
// 拡張子のパターン
const imageExt = /\.(jpg|jpeg|png|gif)$/i;
console.log(imageExt.test("photo.jpg"));  // true
console.log(imageExt.test("photo.PNG"));  // true(大文字小文字を区別しない)
console.log(imageExt.test("document.pdf")); // false

// グループ化して繰り返し
const laugh = /(ha)+/;
console.log(laugh.test("hahaha")); // true

フラグの種類と使い方

フラグは正規表現の動作を変更するためのオプションです。パターンの後ろに付けて使用します。

フラグ 名前 説明
g global すべてのマッチを検索(最初の1つだけでなく)
i ignoreCase 大文字小文字を区別しない
m multiline 複数行モード(^$ が各行の先頭・末尾にマッチ)
s dotAll . が改行文字にもマッチする
u unicode Unicode対応モード
y sticky lastIndexの位置からのみマッチを検索
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const text = "Hello hello HELLO";

// gフラグ:すべてのマッチを検索
console.log(text.match(/hello/g));  // ["hello"]
console.log(text.match(/hello/gi)); // ["Hello", "hello", "HELLO"]

// iフラグ:大文字小文字を区別しない
console.log(/hello/i.test("HELLO")); // true

// mフラグ:複数行モード
const multiLine = "Line1\nLine2\nLine3";
console.log(multiLine.match(/^Line/gm)); // ["Line", "Line", "Line"]

フラグの確認方法

正規表現オブジェクトのプロパティでフラグを確認できます。

1
2
3
4
5
6
const regex = /hello/gi;

console.log(regex.flags);      // "gi"
console.log(regex.global);     // true
console.log(regex.ignoreCase); // true
console.log(regex.multiline);  // false

文字列のマッチ(検索)

正規表現を使って文字列内のパターンを検索する方法を紹介します。

test() メソッド

パターンにマッチするかどうかを true / false で返します。単純な存在確認に最適です。

1
2
3
4
5
6
7
8
const email = "user@example.com";
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

if (emailPattern.test(email)) {
  console.log("有効なメールアドレスです");
} else {
  console.log("無効なメールアドレスです");
}

match() メソッド

文字列のメソッドで、マッチした結果を配列で返します。

1
2
3
4
5
6
7
8
9
const text = "私の誕生日は1990年5月15日です";

// gフラグなし:最初のマッチのみ
const result1 = text.match(/\d+/);
console.log(result1); // ["1990", index: 5, input: "...", groups: undefined]

// gフラグあり:すべてのマッチ
const result2 = text.match(/\d+/g);
console.log(result2); // ["1990", "5", "15"]

exec() メソッド

正規表現のメソッドで、詳細なマッチ情報を取得できます。g フラグと組み合わせてループ処理に使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const text = "apple: 100円, banana: 150円, orange: 120円";
const pattern = /(\w+): (\d+)円/g;

let match;
while ((match = pattern.exec(text)) !== null) {
  console.log(`商品: ${match[1]}, 価格: ${match[2]}円`);
}
// 商品: apple, 価格: 100円
// 商品: banana, 価格: 150円
// 商品: orange, 価格: 120円

search() メソッド

パターンにマッチした最初の位置(インデックス)を返します。マッチしない場合は -1 を返します。

1
2
3
4
const text = "JavaScript is awesome!";

console.log(text.search(/is/));       // 11
console.log(text.search(/python/i)); // -1(マッチなし)

文字列の置換

replace() メソッドと replaceAll() メソッドを使って、パターンにマッチした部分を別の文字列に置き換えます。

replace() メソッド

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const text = "Hello World";

// 最初のマッチのみ置換
console.log(text.replace(/o/, "0")); // "Hell0 World"

// gフラグですべてのマッチを置換
console.log(text.replace(/o/g, "0")); // "Hell0 W0rld"

// 大文字小文字を区別しない
console.log(text.replace(/hello/i, "Hi")); // "Hi World"

キャプチャグループを使った置換

グループ化した部分を $1, $2 などで参照できます。

1
2
3
4
5
6
7
8
9
// 日付フォーマットの変換(YYYY-MM-DD → MM/DD/YYYY)
const date = "2026-01-04";
const formatted = date.replace(/(\d{4})-(\d{2})-(\d{2})/, "$2/$3/$1");
console.log(formatted); // "01/04/2026"

// 名前の順序を入れ替え
const name = "山田 太郎";
const reversed = name.replace(/(\S+)\s+(\S+)/, "$2 $1");
console.log(reversed); // "太郎 山田"

コールバック関数を使った置換

置換処理をより柔軟に行いたい場合は、コールバック関数を使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const text = "りんご: 100円, みかん: 80円, ぶどう: 200円";

// 価格を2倍にする
const doubled = text.replace(/(\d+)円/g, (match, price) => {
  return `${Number(price) * 2}円`;
});
console.log(doubled); // "りんご: 200円, みかん: 160円, ぶどう: 400円"

// 単語を大文字に変換
const words = "hello world javascript";
const upper = words.replace(/\b\w+\b/g, (word) => word.toUpperCase());
console.log(upper); // "HELLO WORLD JAVASCRIPT"

replaceAll() メソッド

ES2021で追加されたメソッドで、すべてのマッチを置換します。

1
2
3
4
5
6
7
const text = "apple, apple, apple";

// replaceAll() を使用
console.log(text.replaceAll("apple", "orange")); // "orange, orange, orange"

// 正規表現を使う場合はgフラグが必須
console.log(text.replaceAll(/apple/g, "orange")); // "orange, orange, orange"

文字列の分割

split() メソッドで正規表現を使って文字列を分割できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 空白文字で分割(複数のスペースにも対応)
const text1 = "apple   banana  orange";
console.log(text1.split(/\s+/)); // ["apple", "banana", "orange"]

// 複数の区切り文字で分割
const text2 = "apple,banana;orange:grape";
console.log(text2.split(/[,;:]/)); // ["apple", "banana", "orange", "grape"]

// 数字で分割(数字を保持)
const text3 = "item1abc2def3";
console.log(text3.split(/(\d)/)); // ["item", "1", "abc", "2", "def", "3", ""]

マッチした部分の抽出

matchAll() メソッド

ES2020で追加されたメソッドで、すべてのマッチを詳細情報付きで取得できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const text = "Email: user1@example.com, user2@test.org";
const emailPattern = /[\w.-]+@[\w.-]+\.\w+/g;

// matchAll() はイテレータを返す
const matches = text.matchAll(emailPattern);

for (const match of matches) {
  console.log(`Found: ${match[0]} at index ${match.index}`);
}
// Found: user1@example.com at index 7
// Found: user2@test.org at index 26

名前付きキャプチャグループ

ES2018から、キャプチャグループに名前を付けられるようになりました。

1
2
3
4
5
6
7
8
9
const dateText = "今日の日付は2026-01-04です";
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const match = dateText.match(pattern);
if (match) {
  console.log(match.groups.year);  // "2026"
  console.log(match.groups.month); // "01"
  console.log(match.groups.day);   // "04"
}

名前付きキャプチャグループを使うと、コードの可読性が大幅に向上します。

実践的な活用例

メールアドレスのバリデーション

1
2
3
4
5
6
7
8
9
function isValidEmail(email) {
  // 基本的なメールアドレスパターン
  const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return pattern.test(email);
}

console.log(isValidEmail("user@example.com"));  // true
console.log(isValidEmail("invalid-email"));     // false
console.log(isValidEmail("user@.com"));         // false

電話番号のフォーマット

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
function formatPhoneNumber(phone) {
  // 数字以外を除去
  const digits = phone.replace(/\D/g, "");
  
  // 10桁または11桁の場合にフォーマット
  if (digits.length === 10) {
    return digits.replace(/(\d{2})(\d{4})(\d{4})/, "$1-$2-$3");
  } else if (digits.length === 11) {
    return digits.replace(/(\d{3})(\d{4})(\d{4})/, "$1-$2-$3");
  }
  
  return phone; // 変換できない場合はそのまま返す
}

console.log(formatPhoneNumber("09012345678")); // "090-1234-5678"
console.log(formatPhoneNumber("0312345678"));  // "03-1234-5678"
console.log(formatPhoneNumber("03-1234-5678")); // "03-1234-5678"

URLからクエリパラメータを抽出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function extractQueryParams(url) {
  const params = {};
  const pattern = /[?&]([^=]+)=([^&]*)/g;
  
  let match;
  while ((match = pattern.exec(url)) !== null) {
    params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
  }
  
  return params;
}

const url = "https://example.com/search?q=JavaScript&page=2&sort=date";
console.log(extractQueryParams(url));
// { q: "JavaScript", page: "2", sort: "date" }

HTMLタグの除去

1
2
3
4
5
6
function stripHtmlTags(html) {
  return html.replace(/<[^>]*>/g, "");
}

const html = "<p>これは<strong>重要な</strong>テキストです。</p>";
console.log(stripHtmlTags(html)); // "これは重要なテキストです。"

パスワード強度のチェック

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function checkPasswordStrength(password) {
  const checks = {
    length: password.length >= 8,
    lowercase: /[a-z]/.test(password),
    uppercase: /[A-Z]/.test(password),
    number: /\d/.test(password),
    special: /[!@#$%^&*(),.?":{}|<>]/.test(password)
  };
  
  const score = Object.values(checks).filter(Boolean).length;
  
  if (score <= 2) return "弱い";
  if (score <= 4) return "普通";
  return "強い";
}

console.log(checkPasswordStrength("abc"));           // "弱い"
console.log(checkPasswordStrength("Password1"));    // "普通"
console.log(checkPasswordStrength("P@ssw0rd!"));    // "強い"

正規表現を使う際の注意点

パフォーマンスに注意

複雑な正規表現や、大きな文字列に対する繰り返し処理はパフォーマンスに影響します。

1
2
3
4
5
// 避けるべきパターン:バックトラッキングが多発する
const badPattern = /a*a*a*a*b/;

// 推奨:シンプルで効率的なパターン
const goodPattern = /a+b/;

特殊文字のエスケープ

メタ文字を文字としてマッチさせたい場合は、バックスラッシュでエスケープが必要です。

1
2
3
4
5
6
// ドメイン名のマッチ(.をエスケープ)
const domain = /example\.com/;

// 金額のマッチ($をエスケープ)
const price = /\$\d+/;
console.log(price.test("$100")); // true

ユーザー入力の正規表現

ユーザーからの入力を正規表現として使用する場合は、特殊文字のエスケープを忘れずに行います。

1
2
3
4
5
6
7
8
9
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

const userInput = "price: $10.00";
const escaped = escapeRegExp(userInput);
const pattern = new RegExp(escaped);

console.log(pattern.test("price: $10.00")); // true

まとめ

本記事では、JavaScriptの正規表現について、基本的な構文から実践的な活用例まで解説しました。正規表現を使いこなすことで、文字列処理のコードがシンプルになり、開発効率が大幅に向上します。

正規表現の学習ポイントを整理すると以下のようになります。

graph TB
    A[正規表現の基礎] --> B[パターン構文]
    A --> C[フラグ]
    B --> D[メタ文字]
    B --> E[文字クラス]
    B --> F[量指定子]
    B --> G[グループ化]
    C --> H[g: グローバル]
    C --> I[i: 大文字小文字無視]
    C --> J[m: 複数行]
    A --> K[メソッド]
    K --> L[test: 存在確認]
    K --> M[match: マッチ取得]
    K --> N[replace: 置換]
    K --> O[split: 分割]

正規表現は最初は難しく感じるかもしれませんが、基本パターンを覚えて少しずつ応用していくことで、確実に習得できます。まずは test()match() を使った簡単なパターンマッチングから始めて、徐々に複雑なパターンに挑戦してみてください。

参考リンク