正規表現を使用すべきではない場合 [閉まっている]


50

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

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

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


ps: " あなたが尋ねている質問は主観的であり、閉じられそうです。 "-したがって、私は正規表現の使用が問題を引き起こすことが知られている例に興味があることを強調したいと思います。


9
正規表現を使用したHTMLの解析は、「多数のバグへの既知の道」ではありません。実際には不可能です。
Kramii復活モニカ

19
それが不可能であるだけでなく、狂気と永遠の損害を
マーティンウィックマン

3
@Jörg:Regexpは正規表現の略です。
ジョレン

3
@Jörg:数学の正規表現とソフトウェアライブラリでの実装には大きな違いがあるのは事実です。また、ほとんどの正規表現ライブラリには、単なる正規言語を受け入れる以上の拡張機能があり、正規表現を呼び出すことが必ずしも適切ではないことも事実です。2つの異なる概念があることに同意します。しかし、それらは同じ名前を持っています。正規表現はまだ略語であり、それ自体は用語ではありません。ソフトウェアライブラリの完全な用語を使用するこのサイトにあるこの例の多く。
ジョレン

2
@Jörg-これらはセマンティクスです。これらのパターンを別の名前で呼び出すことは良い考えかもしれませんが(「正規表現が正規言語用である」という誤りを避けるためだけの場合)、「regexp」/「正規表現」はあまり良い試みではなく、追加の混乱。
コビ

回答:


60

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

  • パーサーがある場合。

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

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

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

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

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

  • 人間の文章を解析するとき。

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

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

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

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

  • コードが読み取られるとき。そして、さまざまな開発者が毎回何度も何度も読みます。

真剣に、私があなたのコードを取り、それをレビューまたは修正しなければならない場合、20行の長い文字列を十分に理解しようとして1週間を費やしたくありません。


9
「真剣に、あなたのコードを受け取ってそれをレビューまたは変更しなければならない場合、20行の長い文字列を十分に理解しようとして1週間を費やしたくありません。」+1!
funkybro

1
これは、スタックオーバーフロー上のステップの姉妹よりもはるかに良い答えです:stackoverflow.com/questions/7553722/...
コビ

1
Perl / PCRE(およびおそらく他の最新の正規表現フレーバーも)(?(DEFINE))を使用している場合は、サブルーチン、名前付きキャプチャグループ、およびアサーションについて読んでください;) yaccなどで書くものと非常に似ています;)
NikiC

2
ブラックリストに登録された単語を解析するために正規表現を使用することは、偶然の誤りです。
ダン・レイ

のような文字列に正規表現を投げることを避ける理由は世界にはありません"<a href='foo'>stuff</a>"。現代の正規表現ではこれに問題はありません。
-tchrist

18

最も重要なことは、構文解析している言語が通常の言語ではない場合です。

HTMLは正規の言語ではないため、正規表現で解析することはできません(難しいかバグのあるコードへの道だけでなく)。


4
違う!最新の正規表現フレーバー(Perl、PCRE、Java、.NETなど)を使用している場合、再帰とアサーションを実行できるため、コンテキストに依存しない文法とコンテキストに依存する文法を照合できます。
NikiC

9
@NikiC。間違ってない。「現代の正規表現フレーバー」は正規表現ではありません(正規言語の解析に使用できるため、名前です)。PREを使用するとさらに多くのことができることに同意しますが、それらを単に「正規表現」とは呼びません(元の質問のように)。
マッテオ

1
現代の正規表現は、あなたのおばあちゃんが教えられたものをはるかに超えているので、正規表現はそれができるので、彼女のアドバイスは重要ではありません。原始的な正規表現でさえ、ほとんどのHTMLスニペットを処理できます。この全面禁止はばかげて非現実的です。この種のことに対して正規表現が作成ました。そして、はい、私は私が話していることを知っています。
-tchrist

12

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
}

1
+1:何度か、「わかりました、具体的には何を一致させようとしているのですか?」「私は何を避けようとしているのですか?」

5

2つのケース:

もっと簡単な方法があるとき

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

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

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

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

0

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

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

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

それ以外の場合のフォーマットの複雑さや複雑さに関係ないことに注意してください。S式は本当に簡単ですが、正規表現では解析できません。一方、CSS2は非常に複雑な言語ですが、再帰構造を含まないため、正規表現で解析できます。(ただし、CSS式は再帰的な構文を持っているため、これはCSS3には当てはまりません。)

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.