6

tl;dr Java で、任意の正規表現を単一の正規表現 (キャプチャではなくマッチング用) に OR/結合する方法はありますか?


私のアプリケーションでは、ユーザーから 2 つのリストを受け取ります。

  1. 正規表現のリスト
  2. 文字列のリスト

(1) のどの正規表現にも一致しなかった (2) の文字列のリストを出力する必要があります。

私は明らかな単純な実装を用意しています((2)のすべての文字列を反復処理します。各文字列について(1)のすべてのパターンを反復処理します。パターンが一致しない場合は、返されるリストに文字列を追加します)、私は疑問に思っていましたすべてのパターンを 1 つのパターンに結合し、正規表現コンパイラに最適化の機会を活用させることができた場合。

正規表現を OR 結合する明白な方法は明らか(regex1)|(regex2)|(regex3)|...|(regexN)ですが、個々の正規表現を制御できないことを考えると、これは正しいことではないと確信しています (たとえば、あらゆる方法の後方/前方参照を含めることができます)。したがって、Javaで任意の正規表現を組み合わせるより良い方法を提案できるかどうか疑問に思っていました.


注: 上記で暗示されているだけですが、明示的にします: 文字列に対してのみ照合しています - キャプチャ グループの出力を使用する必要はありません。

4

1 に答える 1

4

一部の正規表現エンジン (PCRE など) には、構文があり(?|...)ます。これは非キャプチャ グループのようなものですが、すべての交互グループで同じ初期値からカウントされるという優れた機能があります。これはおそらくあなたの問題をすぐに解決するでしょう。したがって、このタスクの言語を切り替えるオプションがある場合は、それでうまくいくはずです.

[編集:実際には、名前付きキャプチャ グループの衝突で問題が発生します。実際、グループ名は再利用できないため、このパターンはコンパイルさえできません。]

そうしないと、入力パターンを操作する必要があります。hyde は後方参照の番号を付け直すことを提案しましたが、もっと簡単なオプションがあると思います: すべてのグループを名前付きグループにすることです。名前が一意であることを確認できます。

基本的に、入力パターンごとに一意の識別子を作成します (たとえば、ID をインクリメントします)。次に、最も難しい部分は、パターン内のキャプチャ グループを見つけることです。正規表現ではこれを行うことはできません。パターンを自分で解析する必要があります。パターン文字列を単純に繰り返し処理する場合に注意すべき点について、いくつかの考えを次に示します。

  • 文字クラス内の括弧はリテラル文字であるため、文字クラスに出入りするときは注意してください。
  • ?:おそらく最もトリッキーな部分: , ?=, ?!, ?<=,が続く開き括弧をすべて無視し?<!ます?>。さらに、オプション設定の括弧:(?idmsuxU-idmsuxU)またはもあり、(?idmsux-idmsux:somePatternHere)これも何もキャプチャしません (もちろん、これらのオプションのサブセットが存在する可能性があり、それらは任意の順序である可能性があり-ます。これもオプションです)。
  • これで、通常のキャプチャ グループまたは名前付き on: のいずれかである開き括弧のみが残るはずです(?<name>。最も簡単な方法は、それらをすべて同じように扱うことです。つまり、番号と名前の両方を持ちます (設定されていない場合、名前は番号と同じです)。次に、これらすべてを次のように書き換えます(?<uniqueIdentifier-md5hashOfName>(ハイフンは実際には名前の一部にすることはできません。増分した数字の後にハッシュが続くだけです-ハッシュは固定長であるため、重複はありません;ほとんど少しでも)。グループが元々持っていた番号と名前を覚えておいてください。
  • バックスラッシュに遭遇したときはいつでも、次の 3 つのオプションがあります。
    1. 次の文字は数字です。番号付き後方参照があります。これらすべての番号を、グループ用に生成した新しいグループ名のk<name>場所に置き換えます。name
    2. 次の文字はk<...>. これを再度、対応する新しい名前に置き換えます。
    3. 次の文字はその他です。スキップしてください。これは、括弧のエスケープとバックスラッシュのエスケープを同時に処理します。
  • Javaは前方参照を許可するかもしれないと思います。その場合は、2 つのパスが必要です。最初にすべてのグループの名前を変更してください。次に、すべての参照を変更します。

すべての入力パターンでこれを実行したら、それらすべてを安全に結合できます|。後方参照以外の機能は、このアプローチで問題を引き起こすことはありません。少なくとも、パターンが有効である限りは。もちろん、入力がa(bありc)d、問題がある場合。しかし、パターンが独自にコンパイルできることを確認しないと、常にそれが発生します。

これが正しい方向への指針になったことを願っています。

于 2012-12-15T22:57:04.057 に答える