私は、人々(特にPerlの世界)が正規表現を神秘化し、普遍的な超大国を(心の中で)与える傾向があることに長い間気づいていました。
この記事では、
2つのエラーがあります。 そして最初のもの
「正規表現はすべてのタスクに等しく適しています。」
ただし、単純なタスクでは、正規表現は効果がありません。
私は次のような決定については黙っています。
if(/./){print "not empty \ n"; }
明らかに、空の文字列と比較するよりも効率的ではありません。
if($ _ ne ""){print "not empty \ n"; }
(ところで、これらの2つの条件は完全に同等ではなく、これにより、最も不適切な瞬間に突然現れるトリックが隠される可能性があります)。
しかし、露骨に不合理な決定があります(それらが悪いと言っているわけではありませんが、それらは間違いなく合理的ではありません)。
簡単なテストを提案します(最後から2ダースの文字が「a」のみで構成されているかどうかを判断します)
ベンチマークqw(:all)を使用します。 私の$ a = 'a'x8000; cmpthese(1_000_000、{ 'regex' => sub {$ a =〜/ a {10}。{10} $ /; }、 'noregex' => sub {substr($ a、-20、10)eq "aaaaaaaaaa"; }、 });
結果にはコメントは不要です。
正規表現noregexを評価する 正規表現414 / s--100% noregex 4413793 / s 1065100%-
<歌詞の余談1>厳密に言えば、テスト用に非ランダムな例を選択しましたが、その本質は変わりません。 正規表現の最適化に興味がある人は、Freedleの正規表現を読むことをお勧めします。 </余談1>
<歌詞の余談2>恐ろしくブレーキングするソリューションが真珠の上でよりエレガントに見えるという事実は、プログラマーが問題を解決するために非合理的なアプローチを使用することを強制するべきではありません。 おそらく、この状況はプログラマーに「最適なソリューションがコンパクトで美しいように見える言語を選択しないように」と思わせるはずです。 Pythonコードには次の2つがあります。
#正規表現オプション(ブレーキ) 再インポート cre = re.compile(r'a {10}。{10} $ ') if(cre.search(string)): #何かをする #明示的な部分文字列比較を伴うオプション if(string [-20:-10] == 'aaaaaaaaaaa'): #何かをする
しかし、これはまったく異なる話です。 </余談2>
そして、2番目のエラーに移ります。
「正規表現はすべてのタスクに等しく適しています。」
今回は、正規表現では解決できないタスクに焦点を当てます。
約4年前、私はある大企業でインタビューを受けました。 インタビューは通常、完全ではなく少し鈍いものでしたが、ついに「ブラケットの正しい配置をチェックする正規表現を作成してください」という質問を受け取りました(つまり、状況 "{<}>"がないことです)。
私はすぐに、最大の括弧の深さは何が許されるか尋ねました。 答えは当惑しました:「誰でも!」
明らかに、質問者はそのような表現が書けることを絶対に確信していたので、私は今それを書きます、そして彼はそれを簡単にチェックします。
なんてつらい誤りでしょう!
誰かがそれを理解する時間がなかったら、説明します。
正規表現は状態マシンを記述します 。 無限の数のブラケットを制御する必要がある場合、 ステートマシンは役に立ちません。
質問は「三角形の辺が1、2、および50センチメートルである場合、三角形の角度の合計はいくらですか」という質問に似ています。 彼は主題の完全な無知を裏切る。
厳密に言えば、
2004年のPerl開発者(混乱しない限り)は、この問題が解決されることを保証しました。 そのようなことのために、「(?? {...})」の構築が考案されました。 しかし、この構造の作業は、通常、次のメッセージを伴って、Perlのい転倒を非常に頻繁に引き起こします。
パニック:グローバルな破壊中にデータコード「b」を解放します。
(文字「b」はエンコーディングによって異なります:-))
驚くことではないが、これらの追加はまだ実験の汚名を取り除くことができない。 PCREでは、この機能は有効になっていません。
開発者はそこで止まりませんでした
最近、新しいメカニズムと構文「(?1)」を導入しました。 このメカニズムは、古いバージョンに固有の不器用さの大部分を免れます。
しかし、私の意見では、再帰的な正規表現は個別に行われるべきであり、「正規」と呼ばれるべきではありません。
正規表現で再帰を使用すると、それらが不規則になります。
彼らはもはや有限状態マシンについて記述していませんが、本格的なチューリングマシンについて記述しています。 このような正規表現では、計算上の問題を解決できます。
したがって、実際には、Perlは正規表現を失いました。 プログラマは、自分の「正規表現」が有限量のメモリを使用することを確信できません。 または、周期的に行かないでください。 (古典的な正規表現はこれらの要件を満たします。循環することはなく、式のコンパイル時に決定される有限のメモリを必要とします。)信頼できる正規表現エンジン。
しかし、これもまたまったく別の話です。 (そして、ところで、正規表現での再帰のトピックはすでにHabrでカバーされています。)
そして、私はただ言いたいだけでした:「注意! 正規表現!」
みなさん、成功しました!