1

テキストから 3 つの単語を取得するには、正規表現を作成する必要があります。単語は 1 つのスペースで区切られます。そして、すべてのシーケンスを提供するわけではないコードを書きました。たとえば、テキスト「ワン ツー スリー フォー ファイブ シックス」の場合、1.ワン ツー スリー 2.フォー ファイブ シックスの 2 つのシーケンスしか得られません。しかし、正規表現ですべてのシーケンスを取得したいので、出力は 1.one two three 2.two three four 3.three four Five. 4.四五六。私の正規表現の何が問題なのか誰か教えてもらえますか? これが私のコードです:

   string input = "one two three four five six";
   string pattern = @"([a-zA-Z]+ ){2}[a-zA-Z]+";
   Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
   MatchCollection matches = rgx.Matches(input);
   if (matches.Count > 0)
   {
       Console.WriteLine("{0} ({1} matches):", input, matches.Count);
       Console.WriteLine();
       foreach (Match match in matches)
           Console.WriteLine(match.Value);
   }
   Console.ReadLine();
4

1 に答える 1

5

正規表現に問題はありません。正規表現がどのように機能するかだけです。一致するものが見つかると、次の一致の検索は、見つけたものの最後から続行されます。一致の幅が消費されます。

だから、これを修正する方法は?1つの方法は、マッチが何も消費しないようにすることです。これを行うには、元のパターンを幅ゼロのポジティブ先読みアサーションに配置します。

string pattern = @"(?=([a-zA-Z]+ ){2}[a-zA-Z]+)";
added --->         ***                        * 

(?=pattern)「この時点で一致するのは、直後に一致するものがある場合のみ」と表示されますpatternが、コンテンツの一致patternは全体的な一致の一部ではないため、消費されません。

ただし、一致の一部ではない場合は、に表示されません。では、match.Valueどのようにして値を取得しますか?シンプル-元のパターン(つまり(?=(pattern)))の周りにキャプチャグループを追加するだけで、キャプチャされたグループは通常どおり結果に表示されます。

string pattern = @"(?=(([a-zA-Z]+ ){2}[a-zA-Z]+))";
added --->            *                        *

foreachこれで、以前と同じようにループを実行できますがmatch.Value、空になります。目的の結果はになりmatch.Groups[1].Valueます。

しかし今、あなたは別の問題を抱えています。あなたの結果は

one two three
ne two three
e two three
two three four
wo three four

等々。これは、単語の途中から始めてもパターンが一致するためです。

これを修正する方法は?

別のゼロ幅アサーションを追加します。今回はネガティブルックビハインドです:(?<![a-zA-Z])。「このポイントの後にパターンが続く場合にのみ一致する」と言うのではなく、「このポイントの前にパターンが続く場合は決して一致しない」言います。したがって、文字が前に付いたポイントで一致することはありません。たとえば、前に。が付いているため、返されません。ne two threeo

string pattern = @"(?<![a-zA-Z])(?=(([a-zA-Z]+ ){2}[a-zA-Z]+))";
added --->         *************

このパターンを使用すると、最終的に期待どおりの結果が得られます。

于 2013-01-22T12:50:09.417 に答える