歴史的視点
ウィキペディアの記事は、正規表現の起源について非常に詳細です(Kleene、1956)。オリジナルの構文は比較的簡単だった*
、+
、?
、|
およびグループ化(...)
。それは簡潔だった(と正式言語は簡潔な数学的表記で表現される傾向があるので、読みやすい、二つは必ずしも反対ではありません)。
後に、構文と機能はエディターで進化し、Perlで成長しました。Perlは設計によって簡潔にしようとしていました(「共通の構造は短くすべきです」)。これにより構文がかなり複雑になりましたが、今では人々は正規表現に慣れており、それらを書くこと(読まない場合)が得意であることに注意してください。書き込み専用である場合があるという事実は、長すぎる場合、通常は適切なツールではないことを示唆しています。
正規表現は、悪用されると判読できなくなる傾向があります。
文字列ベースの正規表現を超えて
代替構文についていえば、のは(すでに存在するものを見てみましょうCL-ppcreで、Common Lispのを)。長い正規表現はppcre:parse-string
、次のように解析できます。
(let ((*print-case* :downcase)
(*print-right-margin* 50))
(pprint
(ppcre:parse-string "^(?:([A-Za-z]+):)?(\\/{0,3})(0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$")))
...そして次の形式になります:
(:sequence :start-anchor
(:greedy-repetition 0 1
(:group
(:sequence
(:register
(:greedy-repetition 1 nil
(:char-class (:range #\A #\Z)
(:range #\a #\z))))
#\:)))
(:register (:greedy-repetition 0 3 #\/))
(:register
(:sequence "0-9" :everything "-A-Za-z"
(:greedy-repetition 1 nil #\])))
(:greedy-repetition 0 1
(:group
(:sequence #\:
(:register
(:greedy-repetition 1 nil :digit-class)))))
(:greedy-repetition 0 1
(:group
(:sequence #\/
(:register
(:greedy-repetition 0 nil
(:inverted-char-class #\? #\#))))))
(:greedy-repetition 0 1
(:group
(:sequence #\?
(:register
(:greedy-repetition 0 nil
(:inverted-char-class #\#))))))
(:greedy-repetition 0 1
(:group
(:sequence #\#
(:register
(:greedy-repetition 0 nil :everything)))))
:end-anchor)
この構文はより冗長であり、以下のコメントを見ると、必ずしも読みやすいとは限りません。そのため、構文がコンパクトではないため、物事が自動的に明確になると想定しないでください。
ただし、正規表現で問題が発生し始めた場合は、正規表現をこの形式に変換すると、コードの解読とデバッグに役立つ場合があります。これは、1文字のエラーを見つけるのが難しい場合がある文字列ベースのフォーマットに対する利点の1つです。
この構文の主な利点は、文字列ベースのエンコードではなく、構造化された形式を使用して正規表現を操作することです。これにより、プログラム内の他のデータ構造のような式を作成および構築できます。上記の構文を使用する場合、これは一般に、小さな部分から式を作成するためです(CodeGolfの回答も参照してください)。あなたの例では、1を書くかもしれません:
`(:sequence
:start-anchor
,(protocol)
,(slashes)
,(domain)
,(top-level-domain) ... )
文字列ベースの正規表現は、文字列の連結および/またはヘルパー関数でラップされた補間を使用して構成することもできます。ただし、コードを乱雑にする傾向のある文字列操作には制限があります(バックスラッシュ$(...)
とバッシュの違いとは異なり、ネストの問題について考えてください。また、エスケープ文字は頭痛の種になります)。
また、上記のフォームではフォームを使用できる(:regex "string")
ため、簡潔な表記とツリーを混在させることができます。そのすべてが、私見を優れた読みやすさと構成可能性に導きます。delnanによって間接的に表現された3つの問題に対処します(つまり、正規表現自体の言語ではありません)。
結論する
ほとんどの場合、簡潔な表記は実際に読み取り可能です。バックトラッキングなどを含む拡張表記を扱う場合は困難がありますが、それらの使用が正当化されることはめったにありません。正規表現を不当に使用すると、表現が読めなくなる可能性があります。
正規表現は文字列としてエンコードする必要はありません。正規表現の作成と作成に役立つライブラリまたはツールがあれば、文字列操作に関連する多くの潜在的なバグを回避できます。
代わりに、形式文法は読みやすく、部分式の命名と抽象化が優れています。通常、端末は単純な正規表現として表されます。
1.正規表現はアプリケーションの定数になる傾向があるため、読み取り時に式を作成することをお勧めします。参照してくださいcreate-scanner
とload-time-value
:
'(:sequence :start-anchor #.(protocol) #.(slashes) ... )