問題に直面したとき、一部の人々は「私は知っている、私は正規表現を使用する」と思う。現在、2つの問題があります。
この引用はどのように理解されるはずですか?
問題に直面したとき、一部の人々は「私は知っている、私は正規表現を使用する」と思う。現在、2つの問題があります。
この引用はどのように理解されるはずですか?
回答:
いくつかのプログラミング技術は、一般のプログラマ(によく理解されていない正規表現、浮動小数点、Perlの、AWK、IoCの ... など)。
これらは、適切な一連の問題を解決するための驚くほど強力なツールです。特に正規表現は、正規言語のマッチングに非常に役立ちます。そして問題の核心があります:普通の言語を記述する方法を知っている人はほとんどいません(これはコンピューターサイエンス理論/面白い記号を使用する言語学の一部です- チョムスキー階層でそれについて読むことができます)。
これらのことを扱うとき、それらを間違って使用すると、元の問題を実際に解決した可能性は低くなります。正規表現を使用してHTMLに一致させる(あまりにも一般的な発生)ことは、エッジケースを見逃すことを意味します。そして今、あなたはまだあなたが解決しなかった元の問題を抱えており、その周りに浮かぶ別の微妙なバグが間違ったソリューションを使用することによって導入されました。
これは、正規表現を使用するべきではないということではなく、解決できる問題のセットを理解し、それらを賢明に解決および使用できないことを理解するように努めるべきだということです。
ソフトウェアを保守するための鍵は、保守可能なコードを書くことです。正規表現を使用することは、その目標に反する可能性があります。正規表現を使用する場合、特別なドメイン固有の言語でミニコンピューター(具体的には非決定性の有限状態オートマトン)を作成しました。この言語で「Hello world」に相当するものを書くのは簡単で、基本的な自信を得ることができますが、特定して修正するのが非常に難しい追加のバグを書くことを避けるために、通常の言語の理解をさらに強化する必要があります正規表現が含まれているプログラムの一部ではありません)。
これで、新しい問題が発生しました。それを解決するために正規表現のツールを選択し(不適切な場合)、今では2つのバグがありますが、どちらも別の抽象化層に隠されているため、どちらも見つけにくいです。
正規表現-特に自明でない表現-は、コーディング、理解、保守が困難になる可能性があります。[regex]
質問者が自分の問題に対する答えが正規表現であると仮定し、その後動けなくなったタグ付きスタックオーバーフローの質問の数だけを見る必要があります。多くの場合、問題は別の方法で解決できます(おそらく解決すべきです)。
これは、正規表現を使用することにした場合、次の2つの問題があることを意味します。
基本的に、彼はあなたの問題を解決する他の方法がない場合にのみ正規表現を使用すべきだと考えていると思います。別のソリューションは、おそらくコーディング、保守、サポートがより簡単になるでしょう。処理速度が遅くなったり、効率が低下したりする場合がありますが、それが重要でない場合は、メンテナンスとサポートの容易さが最優先事項になります。
それは真実の穀物とはいえ、主に冗談です。
正規表現が最適なタスクがいくつかあります。手動で記述された500行の再帰降下パーサーコードを、完全にデバッグするのに約10分かかった1つの正規表現に置き換えました。人々は正規表現を理解してデバッグするのは難しいと言いますが、適切に適用された正規表現は、手作業で設計された巨大なパーサーほどデバッグするのは難しくありません。私の例では、非正規表現ソリューションのすべてのエッジケースをデバッグするのに2週間かかりました。
しかし、叔父ベンを言い換えると:
優れた表現力には大きな責任が伴います。
言い換えれば、正規表現はあなたの言語に表現力を追加しますが、それは与えられたタスクのために最も読みやすい表現モードを選択するプログラマにより多くの責任を負わせます。
最初は、正規表現にとって良いタスクのように見えるものもありますが、そうではありません。たとえば、HTMLなど、ネストされたトークンを持つもの。単純な方法がより明確な場合、人々は正規表現を使用することがあります。たとえばstring.endsWith("ing")
、同等の正規表現よりも理解しやすいです。大きな問題を1つの正規表現に詰め込もうとする場合がありますが、その場合、それを細かく分割する方が適切です。時には、適切な抽象化の作成に失敗し、同じジョブを実行するために適切な名前の関数を作成する代わりに正規表現を何度も繰り返します(おそらく、正規表現で内部的に実装されます)。
何らかの理由で、正規表現には、単一責任やDRYなどの通常のソフトウェアエンジニアリングの原則に対する盲点を作成するという奇妙な傾向があります。だからこそ、それらを愛する人々でさえ、時には問題があると感じるのです。
ジェフアトウッドは、議論のブログ記事で異なる解釈を引き出し、この非常に引用:正規表現:今、あなたは二つの問題を抱えて (おかげ陶酔をリンクするために)
元の1997年のスレッドのJamieの投稿の全文を分析すると、次のことがわかります。
Perlの性質は、他のすべての技術をほとんど除外して、正規表現の使用を奨励しています。それらは、ポイントAからポイントBに到達するための最も「明白な」(少なくとも、それ以上のことを知らない人々にとって)方法です。
最初の引用は、glibでありすぎて真剣に受け取れない。しかし、これは完全に同意します。ジェイミーが意図したことは次のとおりです。正規表現自体が悪ではなく、正規表現の過剰使用は悪です。
正規表現を完全に理解していても、ゴールデンハンマーの問題にぶつかり、正規表現で問題を解決しようとすると、通常のコードで同じことを行う方が簡単で明確になります(CodingHorror:Regex useも参照してください)対正規表現の悪用)。
引用の文脈に目を向け、Atwoodよりも詳細な別のブログ投稿があります:Jeffrey Friedlのブログ:有名な「2つの問題があります」引用のソース
この引用にはいくつかのことが起こっています。
この引用は、以前のジョークを修正したものです。
問題に直面するたびに、「AWKを使用する」と言う人もいます。現在、2つの問題があります。— D.ティルブルック
これは冗談であり、本当の発掘でもありますが、正規表現を他の悪い解決策とリンクすることにより、悪い解決策として強調する方法でもあります。それは本当に重大な瞬間です。
私にとって、この引用は意図的に解釈に対して開かれていることを思い出してください。意味は簡単です。正規表現を使用するというアイデアを単に発表しても、問題は解決しませんでした。さらに、使用している言語とは異なるルールを持つ言語を追加することで、コードの認知の複雑さを増しました。
冗談としては面白いですが、非正規表現ソリューションの複雑さと正規表現ソリューションの複雑さ+正規表現を含めることの追加の複雑さを比較する必要があります。正規表現を追加する追加コストにもかかわらず、正規表現の問題を解決する価値がある場合があります。
正規表現は、他のフォーマットされていないコンテンツよりも維持されますが、実際には、このテキストよりも読みやすいと思われますが、残念ながら、いくつかの実装はフォーマットを許可していないので、不名誉なことはわかりません。
(正規表現は、他のフォーマットされていないコンテンツよりも読み取りや保守が悪くなりません。実際、正規表現はここのこのテキストよりも読みやすい可能性が高いですが、残念ながら、一部の実装ではフォーマットが許可されておらず、一般の人々が悪い評判を持っていますできるとは知らない。)
簡単な例を次に示します。
^(?:[^,]*+,){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の引用は実際には適用されません。
*+
ですか?それはどのように(機能的に)ちょうど違うの*
ですか?
*+
この場合、文字通り何の意味もありません。すべてが固定されており、最大22個までカウントできるオートマトンによって1回のパスで照合できます。これらの非コンマセットの正しい修飾子は単純に古いもの*
です。(さらに、貪欲なマッチングアルゴリズムと貪欲でないマッチングアルゴリズムの違いもありません。これは非常に単純なケースです。)
ChrisFの答えに加えて、正規表現は「コーディング、理解、および保守が困難」であるという悪い点があります。HTMLのように、解析できないものを解析するために人々をだましてしまうほど強力です。「HTMLをどのように解析すればよいですか」に関するSOに関する多くの質問を参照してください。たとえば、SOのすべてで最も壮大な答えです!
正規表現は非常に強力ですが、1つの小さな問題と1つの大きな問題があります。書くのは難しく、読むことはほぼ不可能です。
最良の場合、正規表現を使用することで問題が解決するため、複雑なコードのメンテナンスの問題しかありません。正規表現が適切に得られない場合、元の問題と動作しない読み取り不能なコードの問題の両方があります。
正規表現は、書き込み専用コードと呼ばれることもあります。修正が必要な正規表現に直面すると、表現を理解しようとするよりも最初から始める方が速いことがよくあります。
問題は、正規表現は複雑な獣であり、正規表現を完全に使用する場合にのみ問題を解決できることです。そうしないと、元の問題と正規表現の2つの問題が発生します 。
100行のコードを処理できると主張しますが、100行の明確で簡潔なコードが1行の正規表現よりも優れているという主張をすることもできます。
この証拠を必要とする場合:このSO Classicをチェックアウトするか、SO Regexタグを単純にくぐってください。
意味には2つの部分があります。
2014年にお願いするように、今日の文脈と比較して1997年の文脈のプログラミング言語のイデオロギーに焦点を当てることは興味深いでしょう。ここではこの議論を行いませんが、PerlとPerl自体に関する意見は大きく変わりました。
ただし、2013年のコンテキスト(de l'eau acoulésous les ponts depuis)にとどまるには、Jamie Zawinskiの引用を直接引用した有名なXKCDコミックを使用して引用の再現に焦点を当てることをお勧めします。
まず、私はそれがZawinskiへの参照引用、だったので、この漫画を理解するために問題を抱えていたとジェイ・Zの曲の歌詞の引用、および GNUのの参照program --help -z
フラグ2、私はそれを理解することがあまりにも多くの文化だったので。
私はそれが楽しいことを知っていた、私はそれを感じていたが、私は本当に理由を知りませんでした。人々はしばしばPerlと正規表現について冗談を言っています、特にそれが最も流行のプログラミング言語ではないので、なぜそれが楽しいと思われるのか本当に知りません...多分Perl mongersが愚かなことをするからです。
したがって、最初の引用は、痛いツールを使ったプログラミングによって引き起こされる現実の問題(痛み?)に基づく皮肉な冗談のようです。ハンマーが石工を傷つけるのと同じように、開発者が傷つけることができる場合に開発者が選択するものではないツール(脳、感情)を使用したプログラミング。時々、どのツールが最適かについての大きな議論が起こりますが、それはあなたの好みやプログラミングチームの好み、文化的または経済的な理由の問題であるため、ほとんど価値がありません。これに関するもう1つの優れたXKCDコミック:
正規表現に苦痛を感じている人々を理解することができ、正規表現の設計に適した別のツールがあると彼らは信じています。@ karl-bielefeldtがあなたの質問に優れた表現力で答えると、責任が大きくなり、正規表現は特にこれに懸念を抱きます。開発者が正規表現をどのように扱うか気にしないと、後でコードを保守する人にとっては最終的に苦痛になります。
Damian Conw ayの Perl 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番目の問題です。
/* Multiply the first 10 values in an array by 2. */ for (int i = 0 /* the loop counter */; i < 10 /* continue while it is less than 10 */; ++i /* and increment it by 1 in each iteration */) { array[i] *= 2; /* double the i-th element in the array */ }
正規表現は、本格的な解析よりもトークン化に適しています。
しかし、プログラマーが解析する必要がある驚くほど大きなものは、通常の言語で解析できます(または、さらに悪いことに、通常の言語でほとんど解析できます。コードをもう少し書くだけの場合)。
だから、「ああ、テキストを選択する必要がある、正規表現を使用する」に慣れている場合、プッシュダウンオートマトン、CFGパーサー、またはCFGパーサーに近いものが必要なときに、そのルートを簡単に下ることができますさらに強力な文法。それは通常涙で終わる。
だから、引用はそれほど正規表現を非難しているわけではなく、それらを使用している(そしてよく使われている、実際に非常に有用である)が、正規表現に過度に依存している(具体的には、それらの重要ではない選択) 。
jwzは、その引用で彼のロッカーから外れています。正規表現はどの言語機能とも変わりません-簡単に台無しにされ、エレガントに使いにくく、時には強力で、時には不適切で、よく文書化されていて、しばしば有用です。
浮動小数点演算、クロージャ、オブジェクト指向、非同期I / O、またはその他の名前を付けることができるものについても同じことが言えます。自分が何をしているのかわからない場合、プログラミング言語は悲しくなります。
正規表現が読みにくいと思われる場合は、問題のパターンを消費するための同等のパーサー実装を読んでみてください。多くの場合、正規表現は完全なパーサーよりもコンパクトであるために勝ちます...ほとんどの言語では、同様に高速です。
自己宣伝ブロガーが非修飾ステートメントを作成するため、正規表現(またはその他の言語機能)の使用を遅らせないでください。自分で物事を試してみて、あなたに合ったものを見てください。
これに対する私のお気に入りの詳細な回答は、有名なRob Pikeによって、Googleの内部コードコメントから複製されたブログ投稿で提供されています:http : //commandcenter.blogspot.ch/2011/08/regular-expressions-in-lexing- and.html
要約すると、それらが悪いというわけではありませんが、特に入力の字句解析と解析に関しては、必ずしも適切ではないタスクに頻繁に使用されます。
正規表現は、書くのが難しく、うまく書くのが難しく、他の技術に比べて高価になる可能性があります...一方、Lexersは、(コンパクトではないにしても)正確に書くのがかなり簡単で、テストが非常に簡単です。英数字の識別子を見つけることを検討してください。正規表現( "[a-ZA-Z _] [a-ZA-Z_0-9] *"など)を書くのはそれほど難しくありませんが、単純なループとして書くのはそれほど難しくありません。ただし、ループのパフォーマンスは大幅に向上し、隠れたコードははるかに少なくなります。正規表現ライブラリは大きなものです。識別子を解析するために1つを使用するのは、フェラーリを使用して牛乳の店に行くようなものです。
彼はそれ以上のことを言って、正規表現は例えばテキストエディタでのパターンの使い捨てマッチングでは有用であるが、コンパイルされたコードではめったに使用されるべきではないと主張します。読む価値があります。
正規表現は、高速でダーティなテキスト解析に広く使用されています。これらは、単なる文字列の一致よりも少し複雑なパターンを表現するための優れたツールです。
ただし、正規表現が複雑になると、サーバーの問題が頭を抱えます。
したがって、テキスト処理の問題から始めて正規表現を適用し、解決しようとしていた元の問題と解決しようとしている正規表現を処理する(ただし正しく解決しない)2つの問題が発生するのは非常に簡単です元の問題。