web-dev-qa-db-ja.com

正規表現を使用すべきでない場合は?

正規表現はプログラマーの武器として強力なツールですが、最適な選択ではない場合や、まったく有害な場合さえあります。

簡単な例#1はregexpでHTMLを解析することです-多数のバグへの既知の道。おそらく、これは一般的に 解析 の属性でもあります。

しかし、正規表現のために他に明らかに立ち入り禁止の領域はありますか?


ps: "あなたが質問している質問は主観的であり、閉じられている可能性があります。"-したがって、強調したいのは、正規表現の使用例問題を引き起こすことが知られています。

50
c69

正規表現は使用しないでください。

  • パーサーがある場合

これは [〜#〜] html [〜#〜] に限定されません。単純な有効なXMLは、スキーマを知っていて、決して変更されないことがわかっている場合でも、正規表現で合理的に解析することはできません。

たとえば、 C#のソースコードを解析 は試さないでください。代わりに解析して、意味のあるツリー構造またはトークンを取得します。

  • より一般的には、仕事を行うためのより良いツールがある場合

大文字でも小文字でも検索する必要がある場合はどうでしょうか。正規表現が好きなら、それを使用します。しかし、次々に2つの検索を使用する方が簡単/高速/読みやすいのではないでしょうか。ほとんどの言語では、パフォーマンスが向上し、コードが読みやすくなる可能性があります。

たとえば、Ingoの回答のサンプルコードは、正規表現を使用してはならない場合の良い例です。 fooを検索し、次にbarを検索します。

  • 人間の文章を解析する場合

良い例は、わいせつフィルターです。それを実装するのは一般的に 悪い考え であるだけでなく、正規表現を使用してそれを実行したくなるかもしれません。人間が単語、数字、文を書く方法はたくさんあり、他の人間には理解されますが、正規表現には理解されません。したがって、本当のわいせつをキャッチする代わりに、正規表現は彼女の時間を他のユーザーを傷つけることに費やします。

  • 一部のタイプのデータを検証する場合

たとえば、正規表現を使用して電子メールアドレスを検証しないでください。ほとんどの場合、あなたはそれを間違って行うでしょう。まれなケースでは、あなたはそれを正しく行います そして6 343文字の長さのコーディングホラーで終わります

適切なツールがないと、間違いを犯します。そして、あなたは最後の瞬間にそれらに気づくでしょう、あるいは多分決して気づかないでしょう。クリーンなコードを気にしない場合は、コメントなし、スペースなし、改行なしの20行の文字列を記述します。

  • コードが読み込まれるタイミング。そして、何度も何度も何度も、別の開発者が読んでください。

真剣に、私があなたのコードを取り上げて、それをレビューしたり修正したりする必要がある場合、20行の長い文字列のたくさんのシンボルを理解しようと一週間費やしたくありません。

60

最も重要なこと:解析している言語が 通常の言語 でない場合。

HTMLは通常の言語notであり、正規表現で解析するとnot可能です(難しいか、バグのあるコードへの道)。

18
Matteo

Stackoverflowでは、特定の文字列にnotが含まれているかどうかを調べる正規表現を要求することがよくあります。これは、私見、正規表現の目的を逆転させたものです。解決策が存在する場合(否定後読みアサーションなどを使用する)であっても、その目的のために正規表現を使用し、プログラムロジックで否定ケースを処理する方がはるかに良い場合がよくあります。

例:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}
12
Ingo

2つのケース:

より簡単な方法がある場合

  • ほとんどの言語は、ある文字列が別の文字列のサブセットであるかどうかを判別するINSTRのような単純な関数を提供します。それがあなたがやりたいことなら、より単純な関数を使ってください。独自の正規表現を記述しないでください。

  • 複雑な文字列操作を実行できるライブラリがある場合は、独自の正規表現を作成するのではなく、それを使用してください。

正規表現が十分に強力でない場合

  • パーサーが必要な場合は、パーサーを使用してください。
5
Kramii

正規表現は再帰構造を識別できません。これが基本的な制限です。

JSONを使用してください-これは非常に単純な形式ですが、オブジェクトには他のオブジェクトがメンバーの値(任意の深さ)として含まれている場合があるため、構文は再帰的であり、正規表現で解析できません。一方、CSVは、再帰的な構造を含まないため、正規表現で解析できます

短い正規表現では、パターンがそれ自体を参照することはできません。言うことはできません。構文のこの時点で、もう一度パターン全体と一致します。言い換えると、正規表現は線形にのみ一致し、ネストされたパターンの深さを追跡できるスタックは含まれていません。

それ以外の形式の複雑さや複雑さには関係ありません。 S式は本当に単純ですが、正規表現では解析できません。一方、CSS2はかなり複雑な言語ですが、再帰的な構造を含まないため、は正規表現で解析できます。 (これは、再帰的な構文を持つCSS式のため、CSS3には当てはまりません。)

したがって、正規表現のみを使用してHTMLを解析することは、醜く、複雑で、エラーが発生しやすいためではありません。それは単に不可能であるということです。

再帰的な構造を含むフォーマットを解析する必要がある場合は、少なくとも正規表現の使用をスタックで補足して、再帰的な構造のレベルを追跡する必要があります。これは通常、パーサーの動作方法です。正規表現は「線形」部分を認識するために使用され、正規表現の外のカスタムコードはネストされた構造を追跡するために使用されます。

通常、このような解析は個別のフェーズに分割されます。トークン化は、入力を単語、句読点、角括弧などの「トークン」のシーケンスに分割するために正規表現が使用される最初のフェーズです。解析は、これらのトークンが階層構造、構文ツリーに解析される次のフェーズです。

したがって、HTMLまたはC#を正規表現で解析できないと聞いたときは、正規表現がパーサーの重要な部分であることに注意してください。 only正規表現を使用し、ヘルパーコードを使用しないで、そのような言語を解析することはできません。

0
JacquesB