正規表現はプログラマーの武器の強力なツールですが、最良の選択ではない場合や、まったく有害な場合もあります。
簡単な例#1は、regexpでHTMLを解析することです -多数のバグへの既知の道。おそらく、これも一般的な解析に起因します。
しかし、正規表現のための他の明らかに禁止された領域はありますか?
ps: " あなたが尋ねている質問は主観的であり、閉じられそうです。 "-したがって、私は正規表現の使用が問題を引き起こすことが知られている例に興味があることを強調したいと思います。
正規表現はプログラマーの武器の強力なツールですが、最良の選択ではない場合や、まったく有害な場合もあります。
簡単な例#1は、regexpでHTMLを解析することです -多数のバグへの既知の道。おそらく、これも一般的な解析に起因します。
しかし、正規表現のための他の明らかに禁止された領域はありますか?
ps: " あなたが尋ねている質問は主観的であり、閉じられそうです。 "-したがって、私は正規表現の使用が問題を引き起こすことが知られている例に興味があることを強調したいと思います。
回答:
正規表現を使用しないでください。
これはHTMLに限定されません。スキーマを知っていて、決して変わらないことがわかっていても、単純な有効なXMLは正規表現で合理的に解析できません。
たとえば、C#ソースコードを解析しないでください。代わりに解析して、意味のあるツリー構造またはトークンを取得します。
小文字と大文字の両方の文字を検索する必要がある場合はどうなりますか?正規表現が好きなら、それを使用します。しかし、2つの検索を次々と使用する方が簡単/高速/可読ではありませんか?ほとんどの言語では、パフォーマンスが向上し、コードが読みやすくなります。
たとえば、Ingoの答えのサンプルコードは、正規表現を使用してはならない場合の良い例です。を検索してfoo
から、を検索しbar
ます。
良い例は、わいせつフィルターです。一般にそれを実装するのは悪い考えであるだけでなく、正規表現を使用してそれを行うように誘惑されるかもしれず、あなたはそれを間違って行うでしょう。人間が単語、数字、文章を書くことができる方法はたくさんあり、他の人間に理解されるでしょうが、あなたの正規表現ではありません。ですから、あなたの正規表現は本当のわいせつを捕まえる代わりに、他のユーザーを傷つけることに時間を費やします。
たとえば、正規表現を使用して電子メールアドレスを検証しないでください。ほとんどの場合、間違っています。まれに、正しく実行し、6 343文字の長さのコーディングホラーで終了します。
適切なツールがなければ、間違いを犯すことになります。そして、あなたは最後の瞬間にそれらに気付くでしょう、あるいは多分決してないでしょう。クリーンなコードを気にしない場合は、コメント、スペース、改行なしで20行の文字列を記述します。
真剣に、私があなたのコードを取り、それをレビューまたは修正しなければならない場合、20行の長い文字列を十分に理解しようとして1週間を費やしたくありません。
(?(DEFINE))
を使用している場合は、サブルーチン、名前付きキャプチャグループ、およびアサーションについて読んでください;) yaccなどで書くものと非常に似ています;)
"<a href='foo'>stuff</a>"
。現代の正規表現ではこれに問題はありません。
最も重要なことは、構文解析している言語が通常の言語ではない場合です。
HTMLは正規の言語ではないため、正規表現で解析することはできません(難しいかバグのあるコードへの道だけでなく)。
stackoverflowでは、特定の文字列にこれまたはそれが含まれていないかどうかを調べる正規表現を求める人がよく見られます。これは、私見、正規表現の目的を逆にします。ソリューションが存在する場合(ネガティブな後読みアサーションまたはそのようなものを使用する場合)でも、多くの場合、その目的のために正規表現を使用し、プログラムロジックでネガティブケースを処理する方がはるかに優れています。
例:
# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
# do something
}
# appropriate
if (/foo|bar/) {
# error handling
} else {
# do something
}
2つのケース:
ほとんどの言語は、ある文字列が別の文字列のサブセットであるかどうかを判断するために、INSTRなどの単純な関数を提供します。それがあなたがしたいことであれば、より単純な関数を使用してください。独自の正規表現を記述しないでください。
複雑な文字列操作を実行できるライブラリがある場合は、独自の正規表現を記述するのではなく、それを使用します。
正規表現では、再帰構造を識別できません。これが基本的な制限です。
JSONを取る-これは非常に単純な形式ですが、オブジェクトには他のオブジェクトがメンバー値(任意の深さ)として含まれている可能性があるため、構文は再帰的であり、正規表現では解析できません。一方、CSV は再帰構造を含まないため、正規表現で解析できます。
短い正規表現では、パターンがそれ自体を参照することはできません。言うことはできません:構文のこの時点で、パターン全体に再び一致します。別の言い方をすれば、正規表現は直線的にのみ一致し、ネストされたパターンである深さを追跡できるスタックが含まれていません。
それ以外の場合のフォーマットの複雑さや複雑さに関係ないことに注意してください。S式は本当に簡単ですが、正規表現では解析できません。一方、CSS2は非常に複雑な言語ですが、再帰構造を含まないため、正規表現で解析できます。(ただし、CSS式は再帰的な構文を持っているため、これはCSS3には当てはまりません。)
したがって、正規表現のみを使用してHTMLを解析するのがugい、複雑、またはエラーが発生しやすいからではありません。それは単に不可能だということです。
再帰構造を含む形式を解析する必要がある場合、少なくとも再帰構造のレベルを追跡するためにスタックで正規表現の使用を補足する必要があります。これは通常、パーサーの機能です。正規表現は「線形」部分の認識に使用され、正規表現外のカスタムコードはネストされた構造の追跡に使用されます。
通常、このような解析は別々のフェーズに分割されます。トークン化は、正規表現を使用して、入力を単語、句読点、角かっこなどの「トークン」のシーケンスに分割する最初のフェーズです。解析は、これらのトークンを構文構造の階層構造に解析する次のフェーズです。
そのため、HTMLまたはC#が正規表現で解析できないと聞いた場合、正規表現は依然としてパーサーの重要な部分であることに注意してください。正規表現のみを使用し、ヘルパーコードを使用しないでこのような言語を解析することはできません。