web-dev-qa-db-ja.com

「2つの問題があります」とはどういう意味ですか?

による人気の引用Jamie Zawinski

一部の人々は、問題に直面したときに、「わかっている、私は正規表現を使用する」と考えます。今、彼らは2つの問題を抱えています。

この見積もりはどのように理解されるはずですか?

200
IQAndreas

一部のプログラミングテクノロジーは、一般にプログラマーに理解されていません( 正規表現浮動小数点Perl[〜#〜] awk [〜#〜]IoC ... およびその他 )。

これらは、適切な一連の問題を解決するための驚くほど強力なツールです。特に正規表現は、正規言語の照合に非常に役立ちます。そして、問題の核心があります:通常の言語を記述する方法を知っている人はほとんどいません(これはコンピューターサイエンス理論/面白い記号を使用する言語学の一部です-あなたはそれについて Chomsky階層 で読むことができます)。

これらのことを処理するときに、それらを間違って使用した場合、元の問題を実際に解決したことはほとんどありません。 HTMLに一致させるための正規表現 (あまりにも一般的な出来事)を使用すると、will Edgeのケースを見逃します。そして今、あなたはまだあなたが解決しなかった元の問題を手に入れました、そして周りに浮かぶ別の微妙なバグが間違ったソリューションを使用することによって導入されました。

これは、正規表現を使用してはならないということではなく、解決できる問題のセット、およびそれらを賢く解決して使用できない問題のセットを理解するために取り組む必要があるということです。

ソフトウェアを保守するための鍵は、保守可能なコードを書くことです。正規表現を使用すると、その目標に反する可能性があります。正規表現を使用する場合、特別なドメイン固有の言語でミニコンピューター(具体的には 非決定的有限状態オートマトン )を記述しました。この言語で同等の「Hello world」を記述して初歩的な自信を得るのは簡単ですが、通常の言語を理解することでさらに特定し、特定して修正するのが非常に難しい追加のバグを記述しないようにする必要があります(それらは、正規表現が含まれているプログラムの一部ではありません)。

だから今、あなたは新しい問題を抱えています。 (不適切な場合に)正規表現のツールを選択して解決すると、2つのバグが発生します。これらのバグは、抽象化の別のレイヤーに隠れているため、どちらも見つけるのが困難です。

220
user40980

正規表現-特に重要なもの-は、コーディング、理解、維持が潜在的に困難です。 Stack Overflowのタグ [regex] 質問者は、彼らの問題に対する答えが正規表現であると想定し、その後行き詰まっています。多くの場合、問題は別の方法で解決できます(おそらく解決する必要があります)。

つまり、正規表現を使用する場合、次の2つの問題が発生します。

  1. 解決したかった元の問題。
  2. 正規表現のサポート。

基本的に、問題を解決する方法が他にない場合にのみ正規表現を使用するべきだと彼は言っています。別の解決策は、おそらくコーディング、保守、サポートがより簡単になるでしょう。速度が遅くなるか、効率が低下する可能性がありますが、それがそれほど重要でない場合は、保守とサポートが非常に簡単になることが最も重要です。

95
ChrisF

ほんの少しの真実はあるものの、それは主にほのぼのした冗談です。

正規表現が最適ないくつかのタスクがあります。私はかつて、手動で作成した再帰的降下パーサーコードの500行を、完全にデバッグするのに約10分かかった1つの正規表現に置き換えました。人々は、正規表現を理解してデバッグするのは難しいと言いますが、適切に適用されたものは、巨大な手動設計のパーサーほどデバッグするのが難しくありません。私の例では、非正規表現ソリューションのすべてのEdgeケースをデバッグするのに2週間かかりました。

しかし、ベンおじさんを言い換えると:

優れた表現力には大きな責任が伴います。

言い換えると、正規表現はあなたの言語に表現力を追加しますが、それはプログラマーに与えられたタスクのための最も読みやすい表現モードを選択する責任を負わせます。

いくつかは、最初は正規表現に適しているように見えますが、そうではありません。たとえば、HTMLのように、入れ子になっているトークンを持つもの。単純な方法の方が明確な場合に、正規表現を使用することがあります。たとえば、string.endsWith("ing")は、同等の正規表現よりも理解しやすいです。時々人々は大きな問題を単一の正規表現に詰め込もうとすることがあります。時々人々は適切な抽象化を作成することに失敗し、同じ仕事をするためのよく知られた関数を作成する代わりに正規表現を何度も繰り返します(おそらく正規表現で内部的に実装されます)。

何らかの理由で、正規表現は、単一の責任やDRYなどの通常のソフトウェアエンジニアリングの原則に盲点を作り出す奇妙な傾向があります。愛する人でさえ、時々問題があると思う理由です。

68
Karl Bielefeldt

Jeff Atwoodがこの非常に引用を議論しているブログ投稿で異なる解釈を引き出します: 正規表現:今、2つの問題があります(ありがとう Euphoric リンク)

元の1997年のスレッドでジェイミーの投稿の全文を分析すると、次のことがわかります。

Perlの性質上、他のすべての技法をほとんど排除して、正規表現の使用を奨励しています。それらは、ポイントAからポイントBに到達するための最も「明白な」方法(少なくとも、これ以上何も知らない人にとって)です。

最初の引用は真剣に受け止めるにはあまりにもglibです。しかし、これは完全に同意します。 正規表現自体が悪であることではなく、正規表現の多用が悪であることを示します

doが正規表現を完全に理解していても、 ゴールデンハンマー 問題、正規表現を使用して同じことを行う方が簡単かつ明確だった場合に、正規表現の問題を解決しようとしています( CodingHorrorも参照してください:正規表現の使用と正規表現の乱用の比較( )。

引用のコンテキストを調べ、Atwoodより詳細に説明する別のブログ投稿があります。 Jeffrey Friedlのブログ:有名な「今2つの問題があります」のソース引用

52
IQAndreas

この引用にはいくつかのことが起こっています。

  1. quote は、以前のジョークの言い換えです。

    問題に直面したときはいつでも、「AWKを使用しましょう」と言う人もいます。現在、2つの問題があります。 — D.ティルブルック

    これは冗談であり本物のDigですが、他の悪いソリューションとリンクすることで、正規表現を悪いソリューションとして強調する方法でもあります。それは素晴らしい ハハシリアス 瞬間です。

  2. 私にとって、この引用は意図的に解釈に対して開かれています。意味は単純明快です。正規表現を使用するというアイデアを発表しただけでは問題は解決していません。さらに、使用している言語とは区別されるルールを備えた言語を追加することにより、コードの認識の複雑さを増しています。

  3. ジョークとしては面白いですが、非正規表現ソリューションの複雑さと、正規表現ソリューションの複雑さ+正規表現を含めることの追加の複雑さを比較する必要があります。正規表現の追加には追加コストがかかりますが、正規表現の問題を解決することは価値があります。

30
Jeffery Thomas

正規表現は、フォーマットされていない他のコンテンツよりも保持されます;実際には、ここのテキストよりも簡単に読むことができます。

(正規表現は、他のどのフォーマットされていないコンテンツよりも読みやすく、維持も悪くありません。実際、正規表現はおそらくここのこのテキストよりも読みやすいでしょう-しかし、残念なことに、一部の実装ではフォーマットや一般的な人々を許可していないため、評判が悪いです。それができることを知らない。)


これは簡単な例です。

^(?:[^,]*+,){21}[^,]*+$


どちらにしても、読みにくく、保守もそれほど難しくありませんが、次のようにするとさらに簡単になります。

(?x)    # enables comments, so this whole block can be used in a regex.
^       # start of string

(?:     # start non-capturing group
  [^,]*+  # as many non-commas as possible, but none required
  ,       # a comma
)       # end non-capturing group
{21}    # 21 of previous entity (i.e. the group)

[^,]*+  # as many non-commas as possible, but none required

$       # end of string

これはちょっとおかしな例です(コメント$はコメントに似ていますi++)ですが、それを読んで理解し、維持するのに問題はないはずです。


いつ正規表現が適しているか、そしてそれらが悪い考えであるかについて明確である限り、それらに問題はなく、ほとんどの場合、JWZの引用は実際には適用されません。

21
Peter Boughton

ChrisFの回答 -正規表現は「コーディング、理解、維持が難しい」に加えて、さらに悪いことに、人々をだまして、使用できるものを解析させようとするほど強力です。 t、HTMLのように。 SOの「HTMLの解析方法は?」に関する多数の質問を参照してください。たとえば、すべてのSOで 単一の最も壮大な回答 があります。

14
Frank Shearar

正規表現は非常に強力ですが、小さな問題と大きな問題が1つずつあります。それらは書くのが難しく、読むのもほぼ不可能です。

最良のケースでは、正規表現を使用することで問題が解決されるため、複雑なコードのメンテナンスの問題のみが発生します。正規表現が正しくない場合は、元の問題と、機能しない読み取り不可能なコードの問題の両方があります。

正規表現は、書き込み専用コードと呼ばれることもあります。修正が必要な正規表現に直面すると、多くの場合、表現を理解しようとするよりも、ゼロから始める方が速くなります。

14
Guffa

問題は、正規表現は複雑な獣であり、完全に正規表現を使用する場合にのみ問題を解決することです。そうしないと、2つの問題が発生します。元の問題正規表現です。

100行のコードの作業を実行できると主張しているが、100行の明確で簡潔なコードは1行の正規表現よりも優れているという主張をすることもできます。

これの証明が必要な場合:これをチェックしてください SO Classic または単に SO Regex Tag をくまなく調べてください

10
Ampt

意味には2つの部分があります。

  • まず、元の問題を解決していません。
    これは、正規表現が一般的な問題に 不完全なソリューション を提供することが多いという事実をおそらく参照しています。
  • 次に、選択したソリューションに関連する難易度を追加しました。
    正規表現の場合、追加の難しさはおそらく、複雑さ、保守性、または正規表現を解決することを想定していない問題に正規表現を適合させることに関連する追加の難しさを意味します。
7
tylerl

あなたが2014年にそれを要求するとき、今日のコンテキストと比較して1997年のプログラミング言語のイデオロギーに焦点を当てることは興味深いでしょう。ここではこの議論には入りませんが、PerlとPerl自体に関する意見は大きく変わりました。

ただし、2013のコンテキスト(de l'eau acoulésous les pontsdepuis)にとどまるには、引用符で再現することに焦点を当てることをお勧めします 有名なXKCDジェイミー・ザウィンスキーのものを直接引用したコミック

A comic from XKCD about regexes, Perl and problems

Zawinskiの引用Jay-zの歌詞の引用の引用だったため、最初にこのコミックを理解するのに問題がありました。 and参照GNU program --help -zフラグ 2 なので、理解するには文化が多すぎた。

楽しいことはわかっていましたが、感じていましたが、なぜなのか本当にわかりませんでした。人々は、Perlと正規表現について冗談を言うことがよくあります。特に、それが最先端のプログラミング言語ではないので、なぜそれが楽しいと思われるのか本当にわかりません...多分 Perlモンガーはばかげたことをする のためです。

したがって、最初の引用は、痛いツールを使ったプログラミングによって引き起こされた現実の問題(痛み?)に基づく皮肉な冗談のよ​​うです。ちょうどハンマーが石工を傷つけることができるように、彼が傷つける可能性がある場合に開発者が選択するツール(脳、感情)ではないツールを使用してプログラミングします。場合によっては、どのツールが最適であるかについて大きな議論が起こりますが、それはほとんど価値のない原因ですあなたの好みまたはあなたのプログラミングチームの好み文化的または経済的の理由。これに関する別の優れたXKCDコミック:

A comic from XKCD about programming tools debates

私は、正規表現に苦痛を感じる人々を理解できます、そして彼らは、正規表現が何のために設計されているかにもっと別のツールがより適していると信じています。 @ karl-bielefeldtがあなたの質問に優れた表現力で答えるので、大きな責任が伴います。正規表現は特にこれに関心があります。開発者が正規表現をどのように処理するかを気にしない場合、後でコードを保守する人にとっては結局は苦痛になります。

Damian Conw ay'sPerl Best Practicesからの典型的な例を示す引用によって、引用の再現に関するこの回答で終わります2005年の本)。

彼はこのようなパターンを書くと説明します:

m{'[^\\']*(?:\\.[^\\']*)*'}

...は、次のようなプログラムを書くこと以上受け入れられません

sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;

しかし、それは書き換えることができます、それはまだきれいではありませんが、少なくとも現在は存続可能です。

# Match a single-quoted string efficiently...
m{ '            # an opening single quote
    [^\\']*     # any non-special chars (i.e., not backslash or single quote)
    (?:         # then all of...`
    \\ .        # any explicitly backslashed char
    [^\\']*     #    followed by any non-special chars
    )*          # ...repeated zero or more times
    '           # a closing single quote
}x

この種類の長方形のコード2番目の問題は、明確で保守可能で読みやすい方法でフォーマットできる正規表現ではありません。

7
smonff

コンピュータサイエンスから学ぶべきことが1つあれば、それは Chomsky階層 です。正規表現に関するすべての問題は、それを使用して文脈自由文法を解析しようとする試みから生じると私は言うでしょう。 CFGのネストレベルに制限を課すことができる(または制限を課すことができると考える)と、長くて複雑な正規表現が得られます。

6
Juha Autero

正規表現は、本格的な解析よりもトークン化に適しています。

しかし、プログラマーが解析する必要がある驚くほど大きなもののセットは、通常の言語で解析可能です(さらに悪いことに、通常の言語でほとんど解析可能であり、少しだけコードを記述すれば...)。

したがって、「ああ、テキストを分離する必要があるので、正規表現を使用する」と慣れている場合、プッシュダウンオートマトン、CFGパーサー、またはさらに強力な文法。それは通常涙で終わります。

だから、私は引用がそれほど正規表現を非難しているわけではないと思います、それらはそれらの使用法を持っています(そしてよく使われ、実際に非常に有用です)が、正規表現への過度の依存(または特に、それらの重要でない選択) 。

5
Vatine

jwzは単にその引用で彼のロッカーから外れています。正規表現は他の言語機能と同じです-ねじ込みが簡単、エレガントに使いにくい、時々強力、時々不適切、しばしば十分に文書化され、しばしば有用です。

同じことは、浮動小数点演算、クロージャ、オブジェクト指向、非同期I/O、またはその他の名前を付けることができるものについても言えます。あなたが何をしているかわからない場合、プログラミング言語はあなたを悲しませることがあります。

正規表現が読みにくいと思われる場合は、問題のパターンを利用するための同等のパーサー実装を読んでみてください。正規表現は、完全なパーサーよりもコンパクトであるため、多くの場合、勝ちます。そして、ほとんどの言語では、それらも高速です。

自己宣伝ブロガーが無条件のステートメントを作成するため、正規表現(またはその他の言語機能)を使用することをためらわないでください。自分で試してみて、何がうまくいくか見てみましょう。

3
Brad Clawsie

これに対する私のお気に入りの詳細な回答は、内部のGoogleコードコメントから複製されたブログ投稿で有名なRob Pikeによって提供されています: http://commandcenter.blogspot.ch/2011/08/regular-expressions- in-lexing-and.html

まとめは、それらがbadであるということではありませんが、特にレキシングに関しては、必ずしも適しているわけではないため、タスクに頻繁に使用されますそして、いくつかの入力を解析します。

正規表現は書くのが難しく、うまく書くのが難しく、他のテクノロジーに比べて高くつく可能性があります...一方、レクサーは、正確に書くのがかなり簡単で(コンパクトではない場合)、テストも非常に簡単です。英数字の識別子を見つけることを検討してください。正規表現( "[a-ZA-Z _] [a-ZA-Z_0-9] *"のようなもの)を書くことはそれほど難しくありませんが、単純なループとして書くことはそれほど難しくありません。ただし、ループのパフォーマンスははるかに高くなり、隠されたコードははるかに少なくなります。正規表現ライブラリは大きなものです。識別子を解析するために1つを使用することは、フェラーリを使用して牛乳を購入することに似ています。

彼はそれだけではなく、正規表現は、たとえばテキストエディタでの使い捨てのパターンマッチングですが、コンパイルされたコードなどではほとんど使用されません。読む価値があります。

3
dan mackinlay

正規表現は、迅速でダーティなテキスト解析に広く使用されています。これらは、単なる文字列の一致よりも少し複雑なパターンを表現するための優れたツールです。

ただし、正規表現がより複雑なサーバーの問題を取得すると、頭が浮き上がります。

  1. 正規表現の構文は単純な照合に最適化されており、ほとんどの文字はそれ自体に一致します。これは単純なパターンに最適ですが、ネストが2レベル以上になると、適切に構造化されたコードよりもラインノイズに似たものになります。コードの構造を示すために、インデントとコメントの間に一連の連結された文字列として正規表現を書くことができると思いますが、実際にそれが発生することはまれなようです。
  2. 特定のタイプのテキスト一致のみが正規表現に適しています。ある種のマークアップ言語が動作するための正規表現ベースのパーサーをすばやくダーティに取得していることがよくありますが、より多くのコーナーケースをカバーしようとすると、正規表現がますます複雑になり、読みにくくなります
  3. 正規表現の時間の複雑さは目立たないかもしれません。一致するときにうまく機能するパターンで終了することはそれほど難しくありません ただし、一致しない特定のケースではO(2 ^ n)の複雑さがあります

したがって、テキスト処理の問題から始めて、正規表現を適用して、2つの問題、つまり解決しようとしていた元の問題と、解決しようとしている(ただし正しく解決していない)正規表現を処理するという2つの問題が発生するのは非常に簡単です。元の問題。

0
Peter Green

これは、Alan Perlisのエピグラム#34に関連しています。

文字列は完全なデータ構造であり、渡されるすべての場所でプロセスの重複が多数あります。これは情報を非表示にするのに最適な手段です。

そのため、データ構造として文字列を選択した場合(そして当然、それを操作するアルゴリズムとして正規表現ベースのコードを使用した場合)、たとえそれが機能しても、問題があります:データの不適切な表現に関する設計が不適切で、拡張し、非効率的です。

ただし、うまくいかないことがよくあります。元の問題が解決されていないため、その場合は2つの問題があります。

0
Kaz