27

Java の巨大な正規表現を見て、正規表現全般の保守性について少し考えさせられました。ほとんどの人は (一部の悪意のある perl モンガーを除いて)、正規表現はほとんど保守できないことに同意すると思います。

どうすればこの状況を改善できるかを考えていました。これまでのところ、私が持っている最も有望なアイデアは流暢なインターフェイスを使用することです。例を挙げると、次の代わりに:

Pattern pattern = Pattern.compile("a*|b{2,5}");

このようなものを書くことができます

import static util.PatternBuilder.*

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

Pattern alternative = 
  or(
    string("a").anyTimes(),
    string("b").times(2,5)
  )
  .compile();

この非常に短い例では、正規表現を作成する一般的な方法は、凡庸な才能のある開発者なら誰でも理解できるものです。ただし、それぞれ 80 文字で 2 行以上を埋める不気味な表現について考えてみてください。確かに、(冗長な) 流暢なインターフェースには 2 行だけではなく数行が必要ですが、はるかに読みやすい (したがって保守しやすい) と確信しています。

今私の質問:

  1. 正規表現に対する同様のアプローチを知っていますか?

  2. このアプローチは、単純な文字列を使用するよりも優れていることに同意しますか?

  3. API をどのように設計しますか?

  4. あなたのプロジェクトでそのようなきちんとしたユーティリティを使用しますか?

  5. これを実装するのは楽しいと思いますか? ;)

編集: 単純な構造よりも高いレベルにあるメソッドが存在する可能性があると想像してください。たとえば、正規表現にはありません。

// matches aaaab@example.com - think of it as reusable expressions
Pattern p = string{"a").anyTimes().string("b@").domain().compile();

編集 - コメントの短い要約:

ほとんどの人が正規表現は定着すると考えているのは興味深いことですが、正規表現を読むにはツールが必要であり、正規表現を保守可能にする方法を考えるには賢い人が必要です。流暢なインターフェイスが最善の方法であるかどうかはわかりませんが、賢明なエンジニアがいると確信しています-私たち? ;) - 正規表現を過去のものにするために時間を費やす必要があります - 50 年間私たちと一緒にいるだけで十分だと思いませんか?

懸賞金を開く

報奨金は、正規表現への新しいアプローチの最良のアイデア (コードは不要) に授与されます。

編集 - 良い例:

これが私が話しているパターンの種類です-最初に翻訳できた人への追加の称賛-RegexBuddiesが許可されました(これはApacheプロジェクトからのものです)chiimezに与えられた追加の称賛:これはRFC準拠の電子メールアドレス検証パターンです-ただし、RFC822 ( ex-parrot.comを参照) であり、5322ではありません - 違いがあるかどうかはわかりません - もしそうなら、5322 に適合するパッチに次の追加の称賛を与えます ;)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";
4

19 に答える 19

19

Martin Fowler は別の戦略を提案しています。つまり、正規表現の意味のある部分を取り、それらを変数に置き換えます。彼は次の例を使用します。

 "^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*)" 

になる

   String scoreKeyword = "^score\s+";
   String numberOfPoints = "(\d+)";
   String forKeyword = "\s+for\s+";
   String numberOfNights = "(\d+)";
   String nightsAtKeyword = "\s+nights?\s+at\s+";
   String hotelName = "(.*)";

   String pattern = scoreKeyword + numberOfPoints +
      forKeyword + numberOfNights + nightsAtKeyword + hotelName;

これははるかに読みやすく、保守しやすいものです。

前の例の目標は、次のような文字列のリストから numberOfPoints、numberOfNights、および hotelName を解析することでした。

score 400 for 2 nights at Minas Tirith Airport
于 2009-10-16T20:52:06.107 に答える
18

正規表現の経験がない人にとっては少し簡単かもしれませんが、誰かがあなたのシステムを学んだ後でも、他の場所で通常の正規表現を読むことはできません.

また、あなたのバージョンは正規表現の専門家にとって読みにくいと思います。

次のように正規表現に注釈を付けることをお勧めします。

Pattern pattern = Pattern.compile(
  "a*     # Find 0 or more a        \n" +
  "|      # ... or ...              \n" +
  "b{2,5} # Find between 2 and 5 b  \n",
Pattern.COMMENTS);

これはどの経験レベルでも読みやすく、経験の浅い人にとっては同時に正規表現を教えてくれます。また、構造だけでなく、正規表現の背後にあるビジネス ルールを説明するために、コメントを状況に合わせて調整することもできます。

また、RegexBuddyのようなツールは、正規表現を取得して次のように変換できます。

以下のいずれかの正規表現に一致します (これが失敗した場合にのみ、次の代替を試行します) «a*»
   文字 "a" を文字通り «a*» に一致させます
      ゼロから無制限の間、何度でも、必要なだけお返しします (貪欲) «*»
または、以下の正規表現番号 2 に一致します (これが一致しない場合、一致の試行全体が失敗します) «b{2,5}»
   «b{2,5}» の文字 "b" に一致
      2 回から 5 回の間で、できるだけ多くの回数、必要に応じてお返しします (貪欲) «{2,5}»
于 2009-10-16T16:58:25.617 に答える
10

これは興味深い概念ですが、提示されているように、いくつかの欠陥があります。

しかし、尋ねられた重要な質問に対する最初の答えは次のとおりです。

今私の質問:

1.正規表現に対する同様のアプローチを知っていますか?

まだ言及されていないものはありません。そして、質問と回答を読んで見つけたもの。

2.このアプローチは、単純な文字列を使用するよりも優れている可能性があることに同意しますか?

宣伝どおりに機能すれば、間違いなくデバッグがはるかに簡単になります。

3. APIをどのように設計しますか?

次のセクションの私のメモを参照してください。私はあなたの例とリンクされた.NETライブラリを出発点として取り上げます。

4.プロジェクトでこのような優れたユーティリティを使用しますか?

未定。現在のバージョンの不可解な定期的な表現で問題なく作業できます。また、既存の正規表現を流暢な言語バージョンに変換するためのツールが必要になります。

5.これを実装するのは楽しいと思いますか?;)

実際のコードを書くよりも、より高いレベルの方法で作業するのが楽しいです。これがこの答えであるテキストの壁を説明しています。


ここに私が気付いたいくつかの問題と、それに対処する方法があります。

不明確な構造。

あなたの例は、文字列に連結することによって正規表現を作成しているようです。これはあまり堅牢ではありません。これらのメソッドは、実装とコードをよりクリーンにするため、StringオブジェクトとPatern/Regexオブジェクトに追加する必要があると思います。それに加えて、正規表現が古典的に定義されている方法に似ています。

他の方法で機能していることがわからないという理由だけで、提案されたスキームへの残りのアノテーションは、すべてのメソッドが動作し、Patternオブジェクトを返すことを前提としています。

編集:私は全体を通して次の規則を使用したようです。そこで、それらを明確にして、ここに移動しました。

  • インスタンスメソッド:パターン拡張。例:キャプチャ、繰り返し、アサーションの周りを見てください。

  • 演算子:演算の順序。交互、連結

  • 定数:文字クラス、境界(\ w、$、\ bなどの代わりに)

キャプチャ/クラスタリングはどのように処理されますか?

キャプチャは正規表現の大きな部分です。

各Patternオブジェクトがクラスターとして内部に格納されているのがわかります。(?:パターン)Perl用語で。パターントークンを他のピースに干渉することなく簡単に混合および混合できるようにします。

パターンのインスタンスメソッドとしてキャプチャが実行されることを期待しています。に一致する文字列を格納するための変数を取得します。

pattern.capture(variable)パターンを変数に格納します。キャプチャが複数回一致する式の一部である場合、変数には、パターンに一致するすべての文字列の配列が含まれている必要があります。

流暢な言語は非常にあいまいになる可能性があります。

流暢な言語は、正規表現の再帰的な性質にはあまり適していません。したがって、操作の順序を考慮する必要があります。メソッドを連鎖させるだけでは、非常に複雑な正規表現は使用できません。まさにそのようなツールが役立つ状況。

しますか

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

生産/a*|b{2,5}/または/(a*|b){2,5}/

そのようなスキームはネストされた交代をどのように処理しますか?例えば:/a*|b(c|d)|e/

正規表現で交代を処理する3つの方法があります

  1. オペレーターとして:pattern1 or pattern2 => pattern # /pattern1|pattern2/
  2. クラスメソッドとして:Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
  3. インスタンスメソッドとして:pattern1.or(pattern2) => pattern # /pattern1|patern2/

連結も同じように扱います。

  1. オペレーターとして:pattern1 + pattern2 => pattern # /pattern1pattern2/
  2. クラスメソッドとして:Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
  3. インスタンスメソッドとして:pattern1.then(pattern2) => pattern # /pattern1patern2/

一般的に使用されるパターンを拡張する方法

使用された提案されたスキームは.domain()、一般的な正規表現のようです。ユーザー定義のパターンをメソッドとして扱うことは、新しいパターンを追加することを容易にしません。Javaのような言語では、ライブラリのユーザーは、クラスをオーバーライドして、一般的に使用されるパターンのメソッドを追加する必要があります。

これは、すべてのピースをオブジェクトとして扱うという私の提案によって対処されます。たとえば、ドメインの照合など、一般的に使用される正規表現ごとにパターンオブジェクトを作成できます。キャプチャについての私の以前の考えを考えると、キャプチャされたセクションを含む同じ共通パターンの複数のコピーに対してキャプチャが機能することを保証するのはそれほど難しいことではありません。

さまざまな文字クラスに一致するパターンの定数も必要です。

ゼロ幅はアサーションを見回します

すべてのピースを暗黙的にクラスター化する必要があるという私の考えを拡張します。アサーションを見回すのは、インスタンスメソッドを使用するのも難しいことではありません。

pattern.zeroWidthLookBehind()を生成し(?<patten)ます。


まだ考慮する必要があること。

  • 後方参照:うまくいけば、前に説明した名前付きキャプチャでそれほど難しくはありません
  • 実際に実装する方法。内部についてはあまり考えていません。それは本当の魔法が起こるところです。
  • 翻訳:古典的な正規表現(Perl方言など)と新しいスキームとの間で翻訳するツールが本当に必要です。新しいスキームからの翻訳は、パッケージの一部である可能性があります

すべてをまとめると、メールアドレスに一致するパターンの提案されたバージョンは次のとおりです。

Pattern domain_label = LETTER_CHARACTER + (LETTER_CHARACTER or "-" or DIGIT_CHARACTER).anyTimes()
Pattern domain = domain_label + ("." + domain_label).anyTimes()
Pattern pattern = (LETTER_CHARACTER + ALPHANUMERIC_CHARACTER + "@" + domain).compile

後から考えると、私のスキームは、マーティン・ファウラーの使用中のアプローチから大きく借りています。私はこのようにするつもりはありませんでしたが、それは間違いなくそのようなシステムの使用をより保守しやすくします。また、ファウラーのアプローチ(順序の取得)に関する1つか2つの問題にも対処します。

于 2009-10-19T09:09:42.147 に答える
7

私自身のささやかな試みはGitHubにあります。単純な式に使用する価値はないと思いますが、読みやすさの向上以外にいくつかの利点があります。

  • ブラケットの一致を処理します
  • バックスラッシュ地獄にすぐにつながる可能性のあるすべての「特殊」文字のエスケープを処理します

いくつかの簡単な例:

 // Matches a single digit
    RegExBuilder.build(anyDigit()); // "[0-9]"

 // Matches exactly 2 digits
    RegExBuilder.build(exactly(2).of(anyDigit())); // "[0-9]{2}"

 // Matches between 2 and 4 letters
    RegExBuilder.build(between(2,4).of(anyLetter())); // "[a-zA-Z]{2,4}"

そして、より複雑なもの (多かれ少なかれ電子メールアドレスを検証します):

final Token ALPHA_NUM = anyOneOf(range('A','Z'), range('a','z'), range('0','9'));
final Token ALPHA_NUM_HYPEN_UNDERSCORE = anyOneOf(characters('_','-'), range('A','Z'), range('a','z'), range('0','9'));

String regexText = RegExBuilder.build(
 // Before the '@' symbol we can have letters, numbers, underscores and hyphens anywhere
    oneOrMore().of(
        ALPHA_NUM_HYPEN_UNDERSCORE
    ),
    zeroOrMore().of(
        text("."), // Periods are also allowed in the name, but not as the initial character
        oneOrMore().of(
            ALPHA_NUM_HYPEN_UNDERSCORE
        )
    ),
    text("@"),
 // Everything else is the domain name - only letters, numbers and periods here
    oneOrMore().of( 
        ALPHA_NUM
    ),
    zeroOrMore().of(
        text("."), // Periods must not be the first character in the domain
        oneOrMore().of(
            ALPHA_NUM
        )
    ),
    text("."), // At least one period is required
    atLeast(2).of( // Period must be followed by at least 2 letters (this is the TLD)
        anyLetter()
    )
);
于 2011-12-28T13:58:34.087 に答える
7

API をどのように設計しますか?

Hibernate 基準 API からページを借用します。使用する代わりに:

string("a").anyTimes().or().string("b").times(2,5).compile()

次のようなパターンを使用します。

Pattern.or(Pattern.anyTimes("a"), Pattern.times("b", 2, 5)).compile()

この表記はもう少し簡潔で、パターンの階層/構造が理解しやすいと思います。各メソッドは、最初の引数として文字列またはパターン フラグメントのいずれかを受け入れることができます。

正規表現に対する同様のアプローチを知っていますか?

手に負えない、いいえ。

このアプローチは、単純な文字列を使用するよりも優れていることに同意しますか?

はい、絶対に...リモートで複雑なものに正規表現を使用している場合。非常に短く単純なケースでは、文字列の方が便利です。

あなたのプロジェクトでそのようなきちんとしたユーティリティを使用しますか?

おそらく、実証済み/安定したものになったので... Apache Commonsのようなより大きなユーティリティプロジェクトにそれをロールバックすることはプラスかもしれません.

これを実装するのは楽しいと思いますか? ;)

+1

于 2009-10-23T23:41:24.070 に答える
6

.NET 用の流暢な正規表現ライブラリがあります。

于 2009-10-16T16:23:30.913 に答える
4

私にとっての簡単な答えは、問題を引き起こすのに十分な長さの正規表現(または同じことを行う他のパターンマッチング)に到達したら、おそらくそれらが正しいツールであるかどうかを検討する必要があるということですそもそも仕事のために。

正直なところ、流暢なインターフェイスは、標準の正規表現よりも読みにくいように思えます。非常に短い式の場合、流暢なバージョンは冗長ですが、長すぎません。それは読めます。しかし、長いものの正規表現も同様です。

中規模の正規表現の場合、流暢なインターフェースは扱いにくくなります。不可能ではないにしても、読むのが難しいほど長い。

正規表現が実際には (不可能ではないにしても) 読むのが難しい長い正規表現 (つまり、電子メール アドレス) の場合、流暢なバージョンは 10 ページ前に読むことができなくなりました。

于 2009-10-23T03:34:59.760 に答える
4

簡単な回答: lint とコンパイルの角度からアプローチするのを見てきましたが、これについては考慮すべきだと思います。

長い答え: 私が働いている会社は、エンタープライズ コンテンツ フィルタリング アプリケーション用のハードウェア ベースの正規表現エンジンを作成しています。貴重なサーバーやプロセッサ サイクルを占有するのではなく、ネットワーク ルーターで 20 GB/秒の速度でアンチウイルスまたはファイアウォール アプリケーションを実行することを考えてください。ほとんどのウイルス対策、スパム対策、またはファイアウォール アプリは、核となる一連の正規表現です。

とにかく、正規表現の書き方はスキャンのパフォーマンスに大きな影響を与えます。同じことを行うためにいくつかの異なる方法で正規表現を書くことができ、いくつかの方法ではパフォーマンスが大幅に高速になります。お客様が式を維持および調整できるように、コンパイラとリンターを作成しました。

OPの質問に戻ると、まったく新しい構文を定義するのではなく、リンターを作成します(申し訳ありませんが、私たちのものは独自のものです)正規表現をカットアンドペーストして、レガシー正規表現を分解し、誰かがよりよく理解できるように「流暢な英語」を出力します。また、相対的なパフォーマンス チェックと一般的な変更の提案も追加します。

于 2009-10-20T19:01:28.633 に答える
1

正規表現は、有限状態マシンの記述です。古典的なテキスト表現は必ずしも悪いわけではありません。コンパクトで、比較的明確で、かなりよく採用されています。

より良い表現は状態遷移図である可能性がありますが、それはおそらくソースコードで使用するのは難しいでしょう。

1つの可能性は、さまざまなコンテナーおよびコンバイナーオブジェクトからビルドすることです。

次のようなもの(これを擬似コードから選択した言語に変えることは、熱心な人のための演習として残されています):

domainlabel = oneormore(characterclass( "a-zA-Z0-9-"))
セパレータ=literal( "。")
domain = sequence(oneormore(sequence(domainlabel、separator))、domainlabel)
localpart = oneormore(characterclassnot( "@"))
emailaddress = sequence(localpart、literal( "@")、domain)

上記では、完全な解析には単純なFSM以上のものが必要なため、従う必要のある文法に準拠していない多くの電子メールアドレスが有効であると誤って分類されることに注意してください。ただし、有効なアドレスが無効として誤って分類されるとは思わない。

[^ @] + @([a-zA-Z0-9-] +。)+。([a-zA-Z0-9-] +)に対応する必要があります

于 2009-10-20T13:50:18.370 に答える
1

質問の最後の部分への回答(Kudos用)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";

RFC 準拠の電子メール アドレスに一致します:D

于 2009-10-20T12:37:54.267 に答える
1

私は最近、これと同じ考えを持っていました。

自分で実装しようと思ったのですが、VerbalExpressionsを見つけました。

于 2014-06-30T21:58:18.377 に答える
1

4. あなたのプロジェクトでこのような便利なユーティリティを使用しますか?

私はおそらくそうしないでしょう。これは、仕事に適したツールを使用する場合だと思います。ここには、次のような素晴らしい回答がいくつかあります。Jeremy Stein からの 1579202。私は最近、最近のプロジェクトで正規表現を「取得」しましたが、そのままで非常に便利であることがわかりました。適切にコメントすると、構文を知っていれば理解できます。

「構文を知る」という部分が、人々が正規表現に背を向ける原因だと思います。理解していない人にとっては、難解で不可解に見えますが、それらは強力なツールであり、応用コンピューターサイエンス(たとえば、生計を立てるためのソフトウェアを書く)では有効です。インテリジェントな専門家は、それらを適切に使用する方法を学ぶ必要があり、また、それらを適切に使用できるようにする必要があると思います.

「大いなる力には大いなる責任が伴う」と言うように。私は人々があらゆる場所で正規表現を使用しているのを見てきましたが、時間をかけて構文を徹底的に学習した人が慎重に使用しているため、信じられないほど役に立ちます。私にとって、別のレイヤーを追加すると、ある意味でその目的が無効になるか、少なくともその力が奪われる.

これはあくまで私個人の意見であり、このようなフレームワークを望んでいる人や、正規表現を避けたい人がどこから来ているのかは理解できますが、「正規表現が悪い」という意見を聞くのに時間がかかりません。それらを学び、十分な情報に基づいた決定を下します。

于 2009-10-23T16:31:06.903 に答える
1

探しているものはここにあります:Wizard Design Patternに準拠した正規表現ビルダーです

于 2013-08-27T07:09:08.250 に答える
1

すべての人 (正規表現のマスターと流体インターフェイスの支持者) を満足させるには、流体インターフェイスが適切な生の正規表現パターンを出力できることを確認し、Factory メソッドを使用して通常の正規表現を取得し、それに対して流体コードを生成します。

于 2009-10-23T23:48:47.157 に答える
0

私はそれのために行くと言います、私はそれが実装するのが楽しいと確信しています。

クエリモデル(jQuery、django ORMと同様)を使用することをお勧めします。このモデルでは、各関数がクエリオブジェクトを返すため、それらをチェーン化できます。

any("a").some("b").one("@").some(chars).one(".").some(chars) //a*b+@\w+\.\w+

ここで、charsは任意の文字に合うように事前定義されています。

or選択肢を使用して達成できます:

any("a").choice("x", "z") // a(x|z)

各関数の引数は、文字列または別のクエリにすることができます。たとえば、chars上記の変数はクエリとして定義できます。

//this one is ascii only
chars = raw("a-zA-Z0-9")

したがって、流暢なクエリシステムを使用するのが面倒だと感じた場合は、入力として正規表現文字列を受け入れる「raw」関数を使用できます。

実際、これらの関数は生の正規表現を返すことができ、それらをチェーンすることは単にこれらの生の正規表現文字列を連結することです。

any("a") ---> "a*"
raw("b+") ----> "b+"
one(".") ---> "\."
choice("a", "b") ----> (a|b)
于 2009-10-24T00:19:00.383 に答える
0

正規表現を流暢な API に置き換えることで多くのことがもたらされるかどうかはわかりません。

私は正規表現の達人ではないことに注意してください (正規表現を作成する必要があるたびに、ドキュメントを読み直さなければなりません)。

流暢な API を使用すると、中程度の複雑さの正規表現 (50 文字までとしましょう) が必要以上に複雑になり、最終的には読みにくくなりますが、コード補完のおかげで IDE での正規表現の作成が改善される可能性があります。しかし、コードのメンテナンスは、一般に、コードの開発よりもコストが高くなります。

実際、以前の回答で述べたように、あいまいなケースについて話さずに、新しい正規表現を作成するときに開発者に十分なガイダンスを提供するのに十分なほどスマートな API を持つことができるかどうかさえわかりません。

RFC の正規表現の例について言及しました。私は 99% 確信しています (まだ 1% の希望があります;-)) どの API もその例をこれ以上単純にすることはありませんが、逆に言えば、読みにくくするだけです! とにかく正規表現を使いたくない典型的な例です!

正規表現の作成に関しても、あいまいなパターンの問題により、流暢な API を使用すると、最初は正しい式が得られず、本当に必要なものが得られるまで何度も変更する必要がある可能性があります。

間違いなく、流暢なインターフェイスが大好きです。それらを使用するいくつかのライブラリを開発し、それらに基づいたいくつかのサードパーティ ライブラリを使用しています (Java テスト用の FEST など)。しかし、私は彼らがあらゆる問題の金槌になるとは思いません.

Java だけを考えると、正規表現の主な問題は、Java 文字列定数のバックスラッシュをエスケープする必要があることだと思います。これが、Java で正規表現を作成して理解することを非常に困難にしている 1 つのポイントです。したがって、Java regexp を強化するための最初のステップは、私にとって、文字列定数がバックスラッシュをエスケープする必要のない言語変更 ( la Groovy ) になります。

これまでのところ、Java で正規表現を改善するための私の唯一の提案です。

于 2009-10-25T01:34:01.820 に答える
0

比較してみましょう: 私は (N) Hibernate ICriteria クエリを頻繁に使用してきました。これは、SQL へのFluentマッピングと見なすことができます。私は (そして今でも) それらに熱中していましたが、SQL クエリをより読みやすくしましたか? いいえ、それどころか、別の利点が増えました。プログラムでステートメントを作成したり、それらをサブクラス化したり、独自の抽象化を作成したりすることがはるかに簡単になりました.

私が理解しているのは、特定の言語に新しいインターフェースを使用することは、正しく行われれば価値があることが証明される可能性があるということですが、それをあまり高く評価しないでください。多くの場合、読みやすくはなりません (ネストされた減算文字クラス、後読みでのキャプチャ、流暢に組み合わせるのが難しいいくつかの高度な概念を挙げるための if 分岐)。しかし、多くの場合、柔軟性の向上によるメリットが、構文の複雑さによる追加のオーバーヘッドを上回ります。

可能な代替アプローチのリストに追加し、これを Java のみのコンテキストから外すには、LINQ 構文を検討してください。これは次のようになります (少し不自然です) (とfromはLINQ のキーワードです)。whereselect

// for ^str(aa|bb){3}
from part in mystring
where part startswith "str"
and part hasgroups "aa" or "bb" as first    /* "aa" or "bb" in group 'first' */
and part repeats first 3                    /* repeat group 'first' 3 times */
select part + "extra"                       /* can contain complete statement block */

大まかな考えです、私は知っています。LINQ の良いところは、言語の一種であるコンパイラによってチェックされることです。デフォルトでは、LINQ は流暢な連鎖構文として表現することもできるため、適切に設計されていれば、他のオブジェクト指向言語と互換性があります。

于 2009-10-23T02:39:27.517 に答える