解決策
実世界のテキストを解析するには、H1 や (AH2b+EUH3) のようなコードといった構造化された項目を認識し、それに続くメッセージを捕捉する単一の正規表現が必要になることがよくある。1行で書くと、そのパターンは記号の密集した壁と化した。入れ子のグループ、先読み、量指定子がコメントを入れる余地もなく並び、変更のたびに文字列全体を解きほぐす必要があった。明白な修正にはそれぞれコストが伴った。1行のままにすれば編集のたびに危険が残り、冗長モードを手書きすれば同じサブパターンが現れるたびに重複し、正規表現構築ライブラリを追加すれば新しい構文と依存関係を学ぶことになる。
取られた方策は、パターンをコードとして扱うことだった。著者は各論理単位を一度だけ定義した。すなわち [A-Z]*H のようなコード断片、プラス記号で区切られたコードを包むマルチコード、そして完全なマッチャーであり、それぞれを行ごとにコメントを付けた生の冗長文字列とし、{code} プレースホルダーを介してより小さなものからより大きなパターンを組み立てた。re.VERBOSE は空白とハッシュコメントを無視するため、各断片は上から下へ読める。括弧と選択肢は記号のスープではなく目に見える構造になる。f-string はビルド時に解決されるため、re モジュールに届くものは依然として1つのプレーンなパターン文字列である。
利点はまさに1行正規表現が痛むところにある。各断片は一度だけ定義されるので、文法の変更はそれを埋め込むすべてのパターンを更新する。断片は結合前に re.findall で単独でテストできる。そして新しいものは何もスタックに加わらなかった。著者は長く共存してきた標準ライブラリの2つの機能を使い、この組み合わせに気づくのに3年かかったと認めている。記事は落とし穴を記録している。ハッシュとスペースはエスケープするか文字クラスが必要であり、波括弧の量指定子は f-string 内で二重にする必要があり、インライン (?x) フラグは呼び出し側がフラグを制御するときに冗長モードを機能させ続ける。
達成されたこと
正規表現をコードのように構造化する。各断片をコメント付きの冗長文字列として一度だけ定義し、f-string で最終パターンを組み立てる
うまくいった理由
re.VERBOSE はすでに空白とコメントを無視するので、各断片は標準ライブラリのみを使って文書化されたコードのように読める。
f-string の補間はビルド時に断片を接ぎ合わせ、どの re 呼び出しもそのまま受け入れるプレーンなパターン文字列を残す。
各断片は一度だけ定義されるので、文法の変更は繰り返されるインラインコピーではなく、すべての組み立てられたパターンを更新する。
断片は組み立て前に単独でテストできるので、失敗はそれらの間の結合点に局所化される。
依存関係ゼロで新しい DSL もないため、このアプローチはセットアップなしで任意の Python 3.6+ コードベースに移行できる。
応用できること
1つのパターンが保守に耐えないときは、ライブラリを追加しない。すでに持っている機能 — 可読性のための冗長コメント、再利用のための補間 — を依存関係ゼロで組み合わせる。
その後
2022年5月に公開され、Hacker News で304ポイントと90件のコメントを集めた。反応は、この記事を啓示として扱うものと、正規表現を再利用可能なサブパターンに分割することはすでに一般的な慣行だったと指摘するものに分かれた。コメンターは、補間なしで再利用するためのより強力な仕組み — PCRE と Perl の DEFINE サブルーチンブロック、およびサードパーティの regex モジュール — を指摘し、著者は DEFINE で書いた同じパーサーを示すボーナスセクションを追記した。記事はこれらの注意点が記録されたまま公開されており、その中核的な主張は損なわれていない。依存関係ゼロで、組み立て可能でコメント付きのパターン。
出典をたどる
出典
- The unreasonable effectiveness of f-strings and re.VERBOSE death.andgravity.com · death.andgravity.com
- The unreasonable effectiveness of f-strings and re.verbose — Hacker News discussion Hacker News · news.ycombinator.com ·