Regex道場 ができるまで — リアルタイムハイライトで正規表現を可視化した学習サービスの設計と実装
「正規表現、なんか分かりにくい……」
プログラマーなら一度はこの壁にぶつかります。書籍を読んでも記号が多くて頭に入らない。チュートリアルを見てもコピペで終わる。練習しようにも環境を用意するのが面倒。
パターンを打つたびにマッチ部分がリアルタイムで光ったら、正規表現の動きが直感的に分かる。
それが Regex道場 の出発点です。CmdDojo・SQL道場で確立した「道場アーキテクチャ」を正規表現に応用し、バックエンド不要・インストール不要の練習サービスを作りました。
🎯 なぜ「分かりにくい」がターゲットなのか
正規表現学習の本当のつまずきポイント
「正規表現 入門」でよく見る説明はこうです。
パターン: \d{3}-\d{4}-\d{4}
→ 電話番号にマッチ
これを読んでも「分かった」気にはなりません。実際に打ってみて、マッチした部分が光るのを見て初めて理解できる。
既存の正規表現学習ツールには2種類あります。
- 読み物型 — 解説は丁寧だが練習できない
- チェッカー型 — 「正解か不正解か」だけ返す
Regex道場はどちらでもなく「可視化型」を目指しました。パターンを1文字打つたびにマッチ部分がオレンジでハイライト。「この文字を追加したらここが光った」という試行錯誤そのものが学習になります。
SEO的な狙い
「正規表現 入門」「正規表現 練習」「regex 練習サイト」——これらは継続的に検索需要があります。加えて「分かりにくい」「苦手」といったネガティブキーワードとの組み合わせにも需要があります。
道場シリーズ(CmdDojo・SQL道場・Regex道場)として展開することで、「ブラウザだけで学べる技術練習サイト」というブランドを積み上げる狙いもあります。
🏗️ 技術選定:なぜブラウザネイティブRegExpか
SQL道場ではsql.js(SQLite WASM)を使いましたが、Regex道場には外部ライブラリが不要でした。
| 選択肢 | メリット | デメリット |
|---|---|---|
| ブラウザネイティブ RegExp | ゼロ依存・高速・ES標準 | JavaScript方言に限定 |
| PCRE.js | PCRE互換 | 重い・複雑 |
| re2-wasm | 安全な正規表現 | バックトラック攻撃耐性だが機能制限 |
| バックエンドAPI | 任意エンジン | レイテンシ・コスト |
JavaScriptの RegExp は現代的なWebアプリで十分な機能を持っています。?, +, *, {n,m}, ^, $, \b, (?:...), (?=...) などほとんどのパターンをカバー。学習入門として必要な機能は全て揃っています。
ゼロ依存でオフライン動作可能、レイテンシなし——これがリアルタイム検証の快適さに直結します。
🔧 実装の詳細
RegexEngineの設計
コアロジックは純粋関数として設計しました。
// RegexEngine.ts
export function testRegex(
pattern: string,
flags: string,
testString: string
): RegexTestResult {
try {
const regex = new RegExp(pattern, flags)
const matches: string[] = []
const matchDetails: RegexMatchDetail[] = []
let match: RegExpExecArray | null
const workRegex = new RegExp(pattern, flags.includes("g") ? flags : flags + "g")
while ((match = workRegex.exec(testString)) !== null) {
matches.push(match[0])
matchDetails.push({ match: match[0], index: match.index, length: match[0].length })
if (!flags.includes("g")) break
if (match[0].length === 0) workRegex.lastIndex++ // 無限ループ防止
}
return { matches, matchDetails, error: null }
} catch (e) {
return { matches: [], matchDetails: [], error: (e as Error).message }
}
}
ポイントは exec() ループ による全マッチ取得です。string.match() だとキャプチャグループの情報が失われるため、exec() を使って各マッチの位置(index)も記録しています。
ハイライト表示のしくみ
マッチ結果をオレンジ表示するには、文字列を「マッチ部分」と「それ以外」に分割する必要があります。
export function highlightMatches(
testString: string,
matchDetails: RegexMatchDetail[]
): HighlightSegment[] {
if (matchDetails.length === 0) return [{ text: testString, isMatch: false }]
const segments: HighlightSegment[] = []
let cursor = 0
for (const detail of matchDetails) {
if (cursor < detail.index) {
segments.push({ text: testString.slice(cursor, detail.index), isMatch: false })
}
segments.push({ text: detail.match, isMatch: true })
cursor = detail.index + detail.length
}
if (cursor < testString.length) {
segments.push({ text: testString.slice(cursor), isMatch: false })
}
return segments
}
返却した HighlightSegment[] を <mark> タグで描画するだけでハイライト完成です。
// RegexResult.tsx
{segments.map((seg, i) =>
seg.isMatch
? <mark key={i} className={styles.matchHighlight}>{seg.text}</mark>
: <span key={i}>{seg.text}</span>
)}
/* regex-dojo.module.css */
.matchHighlight {
background: #f0a05040;
border-bottom: 2px solid #f0a050;
border-radius: 2px;
color: inherit;
}
オレンジ半透明の背景 + 下線というスタイルは、VSCodeの検索ハイライトを参考にしました。
リアルタイム検証 vs ボタン実行
SQL道場は「Ctrl+Enter で実行」のボタン駆動でした。正規表現は短いパターンを少しずつ試しながら育てる性質があるため、キーストロークのたびに検証するリアルタイム方式を選択しました。
// RegexEditor.tsx
<input
value={pattern}
onChange={(e) => {
setPattern(e.target.value)
onTest(e.target.value, activeFlags) // onChange で即時実行
}}
/>
debounce は入れていません。正規表現の実行は同期処理でミリ秒以下なので、入力遅延なしでリアルタイム表示できます。
採点ロジックの設計思想
SQL道場では「実行結果(行・列)を検証するvalidate関数」を使いました。Regex道場も同じ思想です。
// CmdDojoのような文字列一致ではなく…
validate: (result) => result.matches.includes("gray") && result.matches.includes("grey")
// パターンを検証しない。結果だけを検証する。
// ↑ これにより gr[ae]y でも (gr)(a|e)(y) でも正解にできる
validate は RegexTestResult | null を受け取ります。
null— パターン未入力result.errorが非null — 不正なパターン([unclosedなど)result.matches— 全マッチの配列result.matchDetails— 各マッチの位置・長さ
この情報があれば「2件マッチしているか」「マッチ内容が正しいか」「エラーなく動いているか」を柔軟に判定できます。
🎨 UIデザインの考え方
道場シリーズの色分け
| サービス | アクセントカラー | テーマ |
|---|---|---|
| HackSim | Teal (#4ec9b0) | ターミナル・ハッキング |
| CmdDojo | Green (#50c878) | Linux・コマンドライン |
| SQL道場 | Blue (#4db6f0) | データベース・クリーン |
| Regex道場 | Orange (#f0a050) | パターン・ハイライト |
オレンジは「ハイライト」の連想から選びました。テキストエディタの検索ハイライトや、ドキュメントの蛍光ペンはオレンジ・黄色系が多い。「正規表現 = マッチ箇所を光らせるもの」というイメージとの一致を狙っています。
パネルレイアウト
┌──────────────────┬────────────────────────┐
│ │ / パターンを入力… │
│ 解説パネル │ フラグ: [g] [i] [m] │
│ ├────────────────────────┤
│ 文字クラス [ ] │ テスト文字列: │
│ メタ文字 \d \w │ Phone: 090-1234-5678 │
│ アンカー ^ $ ├────────────────────────┤
│ 量指定子 + * ? │ マッチ結果: │
│ │ Phone: [090]-[1234]-.. │
│ ├────────────────────────┤
│ │ 11件マッチ │
│ │ 練習問題トラッカー │
└──────────────────┴────────────────────────┘
右パネルのフラグボタン(g / i / m)はトグル式です。正規表現を実際に使う場面でフラグの意味を体感できます。g なしだと最初の1件しかマッチしない——これを視覚的に確かめられます。
🐛 テスト中に見つけたバグ
全レッスンのE2Eテストを本番環境で実施したところ、Lesson 2(文字クラス)のexercise 2で不具合が発覚しました。
バグの内容: validate 関数が matches.length === 10 をチェックしていたが、テスト文字列 "Phone: 090-1234-5678" の数字は 11個。
// バグ(修正前)
validate: (result) => result.matches.length === 10 && ...
// 修正後
validate: (result) => result.matches.length === 11 && ...
「090-1234-5678」の桁数を手で数えず脳内計算で10と書いてしまったミスです。実際は 0・9・0・1・2・3・4・5・6・7・8 で11桁。
この種のバグは単体テストより実際にパターンを打ってみないと気づきにくいです。E2Eテストで全問題を手動検証する価値 を改めて実感しました。
⚡ 開発スピードについて
Regex道場はSQL道場の設計パターンを流用しました。
| 要素 | 流用度 |
|---|---|
| レッスン・コース定義の型 | ほぼそのまま |
| Zustand store + persist | 完全流用 |
| ExerciseTracker UI | レイアウト流用 |
| ページルーティング構成 | 完全流用 |
| CSS Moduleの基本構造 | 流用(色のみ変更) |
| RegexEngine本体 | 新規実装(ブラウザRegExpのラップ) |
| ハイライト表示 | 新規実装(SQL道場にない機能) |
SQL道場との最大の差分は リアルタイムハイライト の部分です。highlightMatches() とCSSの <mark> スタイリングがRegex道場固有の実装です。
「1つ作ると2つ目は半分の時間で作れる」——SQL道場のときも感じましたが、道場シリーズ3作目でさらに加速しています。
📊 コース設計の考え方
入門コース「正規表現入門」の5レッスン構成
| レッスン | テーマ | 学べること |
|---|---|---|
| 01 | リテラル | 文字そのままのマッチ・ドット・エスケープ・iフラグ |
| 02 | 文字クラス | [...]・範囲指定・否定クラス・メタ文字 \d \w \s |
| 03 | アンカー | ^ $ 行頭末・\b 単語境界・gm フラグ |
| 04 | 量指定子 | ? + * {n,m} による繰り返し制御 |
| 05 | グループ・OR | (...) グループ化・` |
この5つを習得すると、現場で必要な正規表現の大半は書けるようになります。最後のexerciseでは「URLを抽出する」実務直結のパターンも練習します。
今後の予定コース
- 実践パターン集 — メール・電話・日付・郵便番号など頻出パターンを体得
- 先読み・後読み —
(?=...)(?<=...)などの高度なパターン - 置換・グループ参照 —
String.replace()との組み合わせ実践
💰 収益化の方向性(構想)
| モデル | 内容 |
|---|---|
| 無料 + プレミアム | 入門コース無料、実践コース以降は有料 |
| 広告 | IT系学習ページは広告単価が高め |
| 企業研修 | 社内コードレビューで使える正規表現研修として提供 |
正規表現は「書ける人が強い」スキルで、エンジニアの採用試験にも出ます。企業向け研修との相性が良いと考えています。
まとめ
Regex道場は「正規表現が分かりにくい」人向けに、リアルタイムハイライトという可視化で正規表現の動きを直感的に伝えるサービスです。
技術的にはブラウザネイティブRegExpをラップした純粋関数エンジンと、マッチ位置からセグメント分割するハイライトロジックが肝です。道場シリーズ3作目として、アーキテクチャの再利用とUIパターンの成熟で、開発速度は上がり続けています。