オンラインで正規表現をテストする方法
正規表現はプログラミングで最も強力なツールの1つであり、同時に正しく書くのが最もイライラするものの1つです。正規表現テスターを使うと、コードを実行し、出力を確認し、何が間違ったかを推測する代わりに、パターンをインタラクティブに作成およびデバッグできます。フィードバックループは反復ごとに数分から数秒に短縮されます。
正規表現テスターを使う理由
コードエディタで正規表現を書くということは、実行時にしかエラーが見えないということです。テスターは次のものを示します:
- ライブのマッチハイライト: パターンを入力するそばから、テキストのどの部分が一致するかが正確に分かります
- キャプチャグループ: デバッグ出力を書かずに、各グループが何をキャプチャするかが分かります
- マッチの詳細: すべてのマッチの正確な位置、長さ、内容
- 置換のプレビュー: 置換を確定する前に、検索置換の結果を確認できます
オンラインで正規表現をテストする手順
- パターンを入力: パターンフィールドに正規表現を入力します。必要に応じてフラグ(グローバル用のg、大文字小文字を区別しないi、複数行のm)を切り替えます。
- テストテキストを貼り付け: マッチングしたいテキストを入力します。マッチはリアルタイムでハイライトされます。
- 結果を表示: 下にキャプチャグループが一覧表示されたすべてのマッチを確認します。「置換」フィールドを使って置換をテストします。
正規表現の簡単な歴史
正規表現は、数学者Stephen Kleeneによって1951年にニューラルネットワークの研究で「正規イベント」の表記法として形式化されました。Ken ThompsonがBell LabsのQEDテキストエディタで1968年に実装し、その後edエディタ(1969年)、最後にgrepユーティリティ(1973年、名前は「global / regular expression / print」から)に実装したとき、理論から実用に飛躍しました。
1987年にLarry Wallが導入したPerlは、正規表現の構文を大幅に拡張しました。非貪欲量指定子、先読み、名前付きグループ、\dや\wのような文字クラスのショートカットなどです。1997年にリリースされたPerl互換正規表現(PCRE)ライブラリは、ほとんどのモダンな言語の事実上の標準になりました。
今日、事実上すべてのプログラミング言語に正規表現の組み込みサポートがありますが、構文はわずかに異なります。JavaScriptのエンジン(ChromeのV8、FirefoxのSpiderMonkey)は高度に最適化されており、ほとんどのオンライン正規表現テスターを動かしています。PHP、Python(reモジュール)、Java(java.util.regex)は近い関係にあるが同一ではない構文を使います。高度な機能では、自分が書いているのがどのフレーバー向けかを知ることが重要です。
知っておく価値のある一般的な正規表現パターン
メールアドレス(基本):
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
URL:
https?://[^\s]+
電話番号(米国):
\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}
日付(YYYY-MM-DD):
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])
IPアドレス(IPv4):
\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b
HEXカラーコード:
#(?:[0-9a-fA-F]{3}){1,2}\b
スラグ(URL安全な識別子):
^[a-z0-9]+(?:-[a-z0-9]+)*$
空白を取り除いた文字列:
^\s*(.*?)\s*$
言語間のフレーバーの違い
正規表現の構文はほとんど移植可能ですが、注意点があります:
- JavaScript: 後読みはES2018で追加されました(
(?<=...)、(?<!...))。Chrome 62以降、Firefox 78以降、Safari 16.4以降でサポートされています。名前付きグループは(?<name>...)で。 - Python:
reモジュールはほぼすべてのPerl機能をサポートします。サードパーティのregexパッケージはさらに多くを追加します(可変長後読み、ファジーマッチング)。 - Java: 単語境界の
\bは同じように動作します。名前付きグループは(?<name>...)を使います。Pattern.compile + matcherパターン。 - PHP:
preg_matchファミリーは内部的にPCREを使います。パターンには区切り文字が必要です:/pattern/flags。 - Go: 線形パフォーマンスを保証するためにRE2構文(後方参照なし、ルックアラウンドなし)を使います。JS / PCREで動作するパターンの一部はGoで失敗します。
- Rust:
regexクレートはデフォルトでRE2を使います。fancy-regexクレートはルックアラウンドを追加します。
テスター(ほぼ常にJavaScriptフレーバー)で正規表現を書くときは、コミットする前に、使ったすべての機能をターゲット言語がサポートすることを確認してください。
よくある落とし穴
- 破滅的バックトラック:
(a+)+bのようなパターンをaaaaaaaaaaaaaaaaaaaaaaaacに対して実行すると、指数的時間がかかることがあります。正規表現エンジンは可能なすべてのグループ化を試みます。所有量指定子((a++)+)やアトミックグループ(?>a+)+を使ってこれを防ぎます。RE2とGoの正規表現は設計上影響を受けません。 - 貪欲 vs 怠惰な量指定子:
a.*bはできるだけ多くにマッチします(貪欲)。a.*?bはできるだけ少なくにマッチします(怠惰)。一方を他方と取り違えることは、「正規表現がマッチしすぎる」という不満の第1位の原因です。 - 複数行モードのアンカー:
^と$はデフォルトで文字列の開始/終了にマッチします。mフラグを付けると、各行の開始/終了にマッチします。これを忘れると不完全な結果になります。 - 文字クラス内の特殊文字:
[...]の中では、ほとんどの特殊文字はその意味を失います。[.]はリテラルなドットにマッチします。ただし]、\、(先頭の)^はまだエスケープが必要です。 - Unicodeと
\w:\wはほとんどのフレーバーで[A-Za-z0-9_]です。つまり、éのようなアクセント付き文字や非ラテン文字にはマッチしません。\p{L}(Unicodeプロパティエスケープ)を使うか、JSではuフラグを渡してください。 - グローバルフラグを忘れる:
gなしでは、String.matchAll()のようなメソッドは例外を投げ、.replace()は最初のマッチのみを置き換えます。テスターはデフォルトでグローバルですが、実際のコードはそうでないかもしれません。 - 入力全体検証のアンカリング:
^foo$は入力全体が「foo」であることを保証します。アンカーがないと、fooは文字列のどこでもマッチし、入力検証においてはセキュリティリスクになります。
正規表現を使うべきでないとき
正規表現は一部のジョブには間違ったツールです:
- HTMLやXMLのパース: ネストされた構造、属性、任意の空白が正規表現を非現実的にします。適切なパーサー(DOMParser、BeautifulSoup、lxml)を使ってください。
- JSONのパース: 同じ理由。
JSON.parse()または同等のものを使ってください。 - ソースコードのパース: ASTパーサー(Acorn、Esprima、AST-grep)は構文を理解します。正規表現はテキストしか見ません。
- メール検証: RFC 5322の有効なメール正規表現は6,000文字以上あります。実際の検証には、代わりに確認メールを送ってください。
- パスワード強度ルール: 「大文字、小文字、数字、特殊文字を含む必要がある」のための複雑な正規表現パターンは保守が困難です。代わりに複数のシンプルなチェックを組み合わせてください。
複数のネストされたグループを持つ100文字を超える正規表現を書いていることに気づいたら、おそらく間違った問題を解いています。
より良い正規表現を書くためのヒント
- シンプルから始める: まず基本的なパターンを動かしてから、複雑さを追加します。完璧な正規表現を一発で書こうとすることはまず成功しません。
- グローバルフラグ(g)を使う: それがないと、テスターは最初のマッチで停止します。
gを付けると、テキスト内のすべてのマッチが見えます。 - エッジケースをテストする: 正規表現は明白なケースにはマッチするかもしれませんが、空文字列、特殊文字、境界条件では失敗するかもしれません。これらをテストテキストに追加してください。
- 特殊文字をエスケープする:
.、*、+、?、(、)、[、]、{、}、\、^、$、|のような文字は正規表現で特別な意味を持ちます。リテラルにマッチさせるには、バックスラッシュを前置します。 - 非キャプチャグループを使う: グループ化のために括弧が必要だがキャプチャは必要ない場合、
(...)の代わりに(?:...)を使います。これによりマッチ結果がよりクリーンに保たれます。 - 複雑なパターンにはコメントを付ける: ほとんどのフレーバーは
xフラグ(拡張モード)をサポートしており、パターン内に空白と# コメントを許可します。50文字を超える正規表現にはこれを使います。 - テストを保存する: 今日のテストテキストで動作する正規表現は、類似の入力に対して永遠に動作するはずです。ドキュメントとして、テストケースを正規表現と一緒にコードベースに保存します。
プライバシーと機密テストデータ
正規表現テスターは完全にブラウザ内で、JavaScriptのネイティブRegExpエンジンを使って動作します。書いたパターン、貼り付けたテストテキスト、見えるマッチはすべてデバイス上に留まります。どのサーバーにもアップロード、ログ、分析されません。
これは正規表現のテストテキストがしばしば機密情報を含むからです。本番のログサンプル(実際のユーザーID、IPアドレス、セッショントークン付き)、CRMから引いたメールリスト、特殊な形式でフォーマットされた顧客データなど。クラウドの正規表現テスターはこれらすべてをサーバー経由でルーティングし、ときには「改善」目的で保存します。ブラウザベースのテスターは、それらすべてに対して露出ゼロです。
よくある質問
私の正規表現は他のプログラミング言語でも動作しますか?
正規表現の構文の大部分は JavaScript、Python、Java、PHP などで共通です。基本パターン(文字クラス、量指定子、アンカー)はどこでも動作します。後読みや名前付きグループのような一部の高度な機能は言語によって異なります。
テストデータはサーバーに送信されますか?
いいえ。すべてのマッチングはブラウザ内で JavaScript ネイティブの RegExp エンジンを使ってローカルに行われます。何も外部に送信されません。
置換をテストできますか?
はい。置換パターン(キャプチャグループには $1、$2 などを使用)を入力すると、検索置換の結果がリアルタイムに表示されます。
オフラインで動作しますか?
はい。ページ読み込み後はインターネット接続なしにブラウザ内で完全に動作します。