ブログ記事

正規表現パズル - 実務で使える10の頻出パターン

「正規表現って呪文みたい...」そんなあなたに贈る、実務でよく使う正規表現パターン集。メール、URL、日本語処理など、コピペで使える実用的なパターンを分かりやすく解説します!

Tips
regex javascript validation patterns tips
正規表現パズル - 実務で使える10の頻出パターンのヒーロー画像

正規表現(Regular Expression、略して Regex)。この言葉を聞いただけで頭が痛くなる人、多いんじゃないでしょうか?

私も最初は「なんだこの暗号…」と思っていました。でも、一度パターンを覚えてしまえば、文字列処理がめちゃくちゃ楽になるんです!今日は、実務でよく使う 10 個のパターンを、実例とともに紹介していきます。

1. メールアドレスの検証

まずは定番中の定番から。でも、完璧なメールアドレスの正規表現って実はものすごく複雑なんです…。

// シンプルで実用的なパターン
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

// 使用例
const validateEmail = (email) => {
  return emailPattern.test(email);
};

console.log(validateEmail('user@example.com')); // true
console.log(validateEmail('test.user+tag@sub.example.co.jp')); // true
console.log(validateEmail('invalid@')); // false
console.log(validateEmail('@example.com')); // false

パターンの解説

  • ^ : 文字列の開始
  • [a-zA-Z0-9._%+-]+ : ユーザー名部分(英数字と一部の記号)
  • @ : アットマーク(そのまま)
  • [a-zA-Z0-9.-]+ : ドメイン名
  • \. : ドット(エスケープが必要)
  • [a-zA-Z]{2,} : TLD(2 文字以上)
  • $ : 文字列の終了

2. URL抽出

SNS やチャットアプリでよく使われる url 抽出パターン:

// URLを抽出する正規表現
const urlPattern =
  /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;

// 使用例
const text = '詳細はhttps://example.com/docs/guide.htmlとhttp://localhost:3000を参照してください。';
const urls = text.match(urlPattern);
console.log(urls);
// ["https://example.com/docs/guide.html", "http://localhost:3000"]

// リンクをクリッカブルにする
const makeClickable = (text) => {
  return text.replace(urlPattern, '<a href="$&" target="_blank">$&</a>');
};

3. 日本語文字列の処理

日本語を扱うときの正規表現は、Unicode の範囲を理解する必要があります:

// 日本語の文字種別パターン
const patterns = {
  hiragana: /[\u3040-\u309F]+/g, // ひらがな
  katakana: /[\u30A0-\u30FF]+/g, // カタカナ
  kanji: /[\u4E00-\u9FAF]+/g, // 漢字
  japanese: /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]+/g, // 全部
};

// 使用例
const text = '私はJavaScriptでプログラミングを勉強しています。';

console.log(text.match(patterns.hiragana)); // ["は", "で", "を", "しています"]
console.log(text.match(patterns.katakana)); // ["プログラミング"]
console.log(text.match(patterns.kanji)); // ["私", "勉強"]

// カタカナをひらがなに変換(簡易版)
const katakanaToHiragana = (str) => {
  return str.replace(/[\u30A0-\u30FF]/g, (match) => {
    return String.fromCharCode(match.charCodeAt(0) - 0x60);
  });
};

console.log(katakanaToHiragana('プログラミング')); // "ぷろぐらみんぐ"

4. 電話番号のフォーマット

日本の電話番号は形式がいろいろあって厄介ですよね:

// 日本の電話番号パターン
const phonePatterns = {
  // ハイフンあり・なし両対応
  mobile: /^0[789]0-?\d{4}-?\d{4}$/,
  landline: /^0\d{1,4}-?\d{1,4}-?\d{4}$/,
  all: /^0\d{1,4}-?\d{1,4}-?\d{4}$/,
};

// フォーマット関数
const formatPhoneNumber = (phone) => {
  // 数字以外を削除
  const numbers = phone.replace(/\D/g, '');

  // 携帯電話
  if (numbers.match(/^0[789]0/)) {
    return numbers.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
  }
  // 市外局番が2桁(東京など)
  else if (numbers.match(/^0[3-9]/)) {
    return numbers.replace(/(\d{2})(\d{4})(\d{4})/, '$1-$2-$3');
  }
  // その他
  return numbers;
};

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

5. HTMLタグの除去

ユーザー入力から html タグを取り除きたいとき:

// HTMLタグを除去する正規表現
const stripHtmlTags = (html) => {
  return html.replace(/<[^>]*>/g, '');
};

// より安全な版(scriptタグの中身も削除)
const stripHtmlSafe = (html) => {
  return html
    .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
    .replace(/<[^>]*>/g, '');
};

const dirty = '<p>こんにちは<script>alert("XSS")</script><b>世界</b></p>';
console.log(stripHtmlTags(dirty)); // "こんにちはalert("XSS")世界"
console.log(stripHtmlSafe(dirty)); // "こんにちは世界"

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

セキュアなパスワードかどうかをチェック:

// パスワード強度チェック
const passwordChecks = {
  // 最低8文字
  minLength: /.{8,}/,
  // 大文字を含む
  hasUpperCase: /[A-Z]/,
  // 小文字を含む
  hasLowerCase: /[a-z]/,
  // 数字を含む
  hasNumber: /\d/,
  // 特殊文字を含む
  hasSpecialChar: /[!@#$%^&*(),.?":{}|<>]/,
};

const checkPasswordStrength = (password) => {
  const strength = {
    score: 0,
    feedback: [],
  };

  if (!passwordChecks.minLength.test(password)) {
    strength.feedback.push('8文字以上にしてください');
  } else {
    strength.score++;
  }

  if (!passwordChecks.hasUpperCase.test(password)) {
    strength.feedback.push('大文字を含めてください');
  } else {
    strength.score++;
  }

  // ... 他のチェックも同様に

  return strength;
};

7. 全角・半角の変換

日本語入力でよくある全角・半角の統一:

// 全角数字を半角に変換
const zenkakuToHankaku = (str) => {
  return str.replace(/[0-9]/g, (s) => {
    return String.fromCharCode(s.charCodeAt(0) - 0xfee0);
  });
};

// 半角カナを全角に変換(一部のみ)
const hankakuKanaToZenkaku = (str) => {
  const kanaMap = {
    ア: 'ア',
    イ: 'イ',
    ウ: 'ウ',
    エ: 'エ',
    オ: 'オ',
    // ... 省略
  };

  return str.replace(/[ア-ン]/g, (match) => kanaMap[match] || match);
};

console.log(zenkakuToHankaku('12345')); // "12345"

8. クレジットカード番号の検証

クレジットカード番号のフォーマットチェック(実際の検証には Luhn アルゴリズムも必要):

const creditCardPatterns = {
  visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
  mastercard: /^5[1-5][0-9]{14}$/,
  amex: /^3[47][0-9]{13}$/,
  jcb: /^(?:2131|1800|35\d{3})\d{11}$/,
};

const detectCardType = (number) => {
  const cleaned = number.replace(/\s/g, '');

  for (const [type, pattern] of Object.entries(creditCardPatterns)) {
    if (pattern.test(cleaned)) {
      return type;
    }
  }
  return 'unknown';
};

// 番号をマスクする
const maskCreditCard = (number) => {
  return number.replace(/\d(?=\d{4})/g, '*');
};

console.log(maskCreditCard('4111 1111 1111 1111')); // "**** **** **** 1111"

9. ファイル拡張子の判定

アップロードされたファイルの種類をチェック:

const fileTypePatterns = {
  image: /\.(jpg|jpeg|png|gif|webp|svg)$/i,
  video: /\.(mp4|avi|mov|wmv|flv)$/i,
  audio: /\.(mp3|wav|ogg|m4a)$/i,
  document: /\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$/i,
  code: /\.(js|ts|jsx|tsx|py|java|cpp|c|go|rs)$/i,
};

const getFileType = (filename) => {
  for (const [type, pattern] of Object.entries(fileTypePatterns)) {
    if (pattern.test(filename)) {
      return type;
    }
  }
  return 'other';
};

console.log(getFileType('photo.jpg')); // "image"
console.log(getFileType('index.js')); // "code"
console.log(getFileType('document.pdf')); // "document"

10. 空白文字の正規化

見えない文字や余計な空白を整理:

// 様々な空白文字を処理
const whitespacePatterns = {
  // 連続する空白を1つに
  multipleSpaces: /\s+/g,
  // 行頭行末の空白
  trim: /^\s+|\s+$/g,
  // 全角スペースを半角に
  zenkakuSpace: / /g,
  // 改行の統一
  lineBreaks: /\r\n|\r|\n/g,
};

const normalizeText = (text) => {
  return text
    .replace(whitespacePatterns.zenkakuSpace, ' ') // 全角→半角
    .replace(whitespacePatterns.multipleSpaces, ' ') // 連続空白を1つに
    .replace(whitespacePatterns.trim, '') // 前後の空白削除
    .replace(whitespacePatterns.lineBreaks, '\n'); // 改行を統一
};

const messy = '  こんにちは  世界  \r\n  Hello   World  ';
console.log(normalizeText(messy)); // "こんにちは 世界\nHello World"

デバッグのコツ

正規表現をデバッグするときの私のおすすめツール:

  1. regex101.com - リアルタイムで動作確認できる
  2. RegExr - ビジュアルな説明付き
  3. Chrome DevTools - コンソールで即座にテスト
// デバッグ用ヘルパー関数
const regexDebug = (pattern, text) => {
  console.log(`Pattern: ${pattern}`);
  console.log(`Text: "${text}"`);
  console.log(`Match: ${pattern.test(text)}`);

  const matches = text.match(pattern);
  if (matches) {
    console.log('Matches:', matches);
  }
};

まとめ

正規表現は最初は難しく感じますが、よく使うパターンを覚えておけば、文字列処理が格段に楽になります。今回紹介したパターンは、そのままコピペして使えるものばかりなので、ぜひ活用してください!

ちなみに、私の好きな正規表現ジョークがあります: 「正規表現で問題を解決しようとすると、問題が 2 つになる」

…確かに、複雑になりすぎると逆に大変ですよね。適材適所で使っていきましょう!

次回は「シェルスクリプト高速化テクニック」について解説します。処理時間を劇的に短縮する方法、お楽しみに!

この記事は役に立ちましたか?

Daily Hackでは、開発者の皆様に役立つ情報を毎日発信しています。