1

これはクロスワード問題です。例:

  • 答えは「r」で始まり「r」で終わる6文字の単語です
  • したがって、パターンは「r....r」です
  • 未知の 4 文字は、文字 "a"、"e"、"i"、"p" のプールから引き出す必要があります。
  • 各文字は 1 回だけ使用する必要があります
  • 候補の6文字の単語の大きなリストがあります

解決策:「レイピア」または「修理」。

パターン「r....r」のフィルタリングは簡単ですが、「不明」スロットに [aeip] を含む単語を見つけるのは私には不可能です。

この問題は正規表現の影響を受けやすいですか、それとも徹底的な方法で解決する必要がありますか?

4

7 に答える 7

4

これを試して:

r(?:(?!\1)a()|(?!\2)e()|(?!\3)i()|(?!\4)p()){4}r

...またはより読みやすく:

r
(?:
  (?!\1) a () |
  (?!\2) e () |
  (?!\3) i () |
  (?!\4) p ()
){4}
r

空のグループはチェック マークとして機能し、各文字が消費されるとチェックマークが付きます。たとえば、一致する単語が である場合、この構文によって一致する最初の文字はrepairtheになります。e正規表現が後で別の正規表現と一致しようとするとe、その代替は一致しません。グループ #2 が試合に参加しているため、否定的な先読み(?!\2)は失敗します。

本当に素晴らしいのは、重複した文字を含む文字列でも同様に機能することです。あなたのredeem例を見てください:

r
(?:
  (?!\1) e () |
  (?!\2) e () |
  (?!\3) e () |
  (?!\4) d ()
){4}
m

最初の選択肢が消費された後、e最初の選択肢は事実上無効になるため、代わりに 2 番目の選択肢が使用されます。等々...

残念ながら、この手法はすべての正規表現で機能するわけではありません。1 つには、空/失敗したグループ キャプチャをすべて同じように扱うわけではありません。ECMAScript 仕様では、参加していないグループへの参照は常に成功する必要があると明示的に述べています。

正規表現フレーバーは、前方参照、つまり、正規表現で参照するグループの前に現れる後方参照もサポートする必要があります。( ref ) 私が知っている .NET、Java、Perl、PCRE、Ruby で動作するはずです。

于 2013-04-17T19:55:35.657 に答える
0

よりスケーラブルな解決策 (文字または位置ごとに \1、\2、\3 などを記述する必要はありません) は、否定先読みを使用して、各文字が後で発生しないことを表明することです。

^r(?:([aeip])(?!.*\1)){4}r$

次のように読みやすく:

^r
(?:
  ([aeip])
  (?!.*\1)
){4}
r$

改良点

これは、提供された状況で機能する迅速な解決策でしたが、より堅牢なバージョンにするための追加の制約がいくつかあります。

  • 「文字のプール」が文字列の末尾と一部の文字を共有する可能性がある場合は、先読みにパターンの末尾を含めます。

    ^r(?:([aeip])(?!.*\1.*\2)){4}(r$)
    

    (すべての正規表現フレーバーで意図したとおりに機能しない可能性があります。その場合は、使用する代わりにパターンの最後をコピーして貼り付けます\2)

  • 一部の文字が 1 回だけでなく、別の固定回数存在する必要がある場合は、この回数を共有するすべての文字に対して個別の先読みを追加します。たとえば、1 つの "a" と 1 つの "p" を含む "r....r" と 2 つの "e" は、この正規表現に一致します (ただし、"rapper" と "repeer" は一致しません)。

    ^r(?:([ap])(?!.*\1.*\3)|([e])(?!.*\2.*\2.*\3)){4}(r$)
    

    非キャプチャ グループには 2 つの選択肢があります。([ap])(?!.*\1.*\3)「a」または「p」に一致し、別のグループが終わるまでどこにも([e])(?!.*\2.*\2.*\3)続きません。「e」に一致し、他の 2 つのグループが終わるまでどこにも続きません (したがって、最初のグループでは失敗します)。全部で 3 つある場合は 1 つ)。ところで、このソリューションには上記のソリューションが含まれていますが、パターンの最後はここにシフトされています\3(また、フレーバーについての注意を参照してください)。

于 2016-08-09T11:56:01.563 に答える
0

各「。」を置き換えてみませんか。'[aeip]' を使って元のパターンに?

正規表現 string で終わるでしょうr[aeip][aeip][aeip][aeip]r

もちろん、これは に短縮できますr[aeip]{4,4}rが、一般的なケースで実装するのは面倒であり、おそらくコードを改善することはありません。

これは、文字の重複使用の問題には対応していません。私がそれをコーディングしている場合、正規表現の外側のコードでそれを処理します-主に、正規表現は私が処理したいよりも複雑になるためです。

于 2013-04-17T15:16:38.887 に答える
0

文字列を比較するために使用されているフロント エンド言語は何ですか。Java か .net か ...

ここにJavaを使用した例/疑似コードがあります

    String mandateLetters = "aeio"
    String regPattern = "\\br["+mandateLetters+"]*r$";  // or if for specific length \\br[+mandateLetters+]{4}r$

    Pattern pattern = Pattern.compile(regPattern);
    Matcher matcher = pattern.matcher("is this repair ");

    matcher.find();
于 2013-04-17T15:10:49.487 に答える