0

最近、1 つの C# Regex API が非常に煩わしいことに気付きました。

私は正規表現を持っています(([0-9]+)|([a-z]+))+。一致したすべての文字列を検索したい。コードは以下のようなものです。

string regularExp = "(([0-9]+)|([a-z]+))+";
string str = "abc123xyz456defFOO";

Match match = Regex.Match(str, regularExp, RegexOptions.None);
int matchCount = 0;

while (match.Success)
{
    Console.WriteLine("Match" + (++matchCount));

    Console.WriteLine("Match group count = {0}", match.Groups.Count);
    for (int i = 0; i < match.Groups.Count; i++)
    {
        Group group = match.Groups[i];
        Console.WriteLine("Group" + i + "='" + group.Value + "'");
    }

    match = match.NextMatch();
    Console.WriteLine("go to next match");
    Console.WriteLine();
}

出力は次のとおりです。

Match1
Match group count = 4
Group0='abc123xyz456def'
Group1='def'
Group2='456'
Group3='def'
go to next match

すべての group.Value が最後に一致した文字列 (「def」と「456」) のようです。group.Value の代わりに group.Captures を使用する必要があることを理解するために、しばらく時間を費やしました。

string regularExp = "(([0-9]+)|([a-z]+))+";
string str = "abc123xyz456def";
//Console.WriteLine(str);

Match match = Regex.Match(str, regularExp, RegexOptions.None);
int matchCount = 0;

while (match.Success)
{
    Console.WriteLine("Match" + (++matchCount));

    Console.WriteLine("Match group count = {0}", match.Groups.Count);
    for (int i = 0; i < match.Groups.Count; i++)
    {
        Group group = match.Groups[i];
        Console.WriteLine("Group" + i + "='" + group.Value + "'");

        CaptureCollection cc = group.Captures;
        for (int j = 0; j < cc.Count; j++)
        {
            Capture c = cc[j];
            System.Console.WriteLine("    Capture" + j + "='" + c + "', Position=" + c.Index);
        }
    }

    match = match.NextMatch();
    Console.WriteLine("go to next match");
    Console.WriteLine();
}

これは出力されます:

Match1
Match group count = 4
Group0='abc123xyz456def'
    Capture0='abc123xyz456def', Position=0
Group1='def'
    Capture0='abc', Position=0
    Capture1='123', Position=3
    Capture2='xyz', Position=6
    Capture3='456', Position=9
    Capture4='def', Position=12
Group2='456'
    Capture0='123', Position=3
    Capture1='456', Position=9
Group3='def'
    Capture0='abc', Position=0
    Capture1='xyz', Position=6
    Capture2='def', Position=12
go to next match

さて、なぜ API 設計がこのようになっているのか疑問に思います。Group.Value が最後に一致した文字列のみを返すのはなぜですか? このデザインはよく見えません。

4

1 に答える 1

2

主な理由は歴史的です。正規表現は常にそのように機能し、Perl以降にまで遡ります。しかし、それは本当に悪いデザインではありません。通常、そのようなすべての一致が必要な場合は、最も外側の数量詞(+この場合)を省略し、のMatches()代わりにメソッドを使用しMatch()ます。すべての正規表現対応言語は、それを行う方法を提供します。PerlまたはJavaScriptでは、/gモードで照合を行います。Rubyでは、このscanメソッドを使用します。Javaでは、がfind()返されるまで繰り返し呼び出しますfalse。同様に、置換操作を実行している場合は$1、プレースホルダー(言語に応じて、、、、、)を使用して 、キャプチャされたサブ文字列をプラグインし直すことができます。$2\1\2

一方、.NETがCaptureCollectionsで行うように、中間のキャプチャグループの一致を取得する機能を提供するPerl5から派生した正規表現フレーバーは他にありません。そして、私は驚かない。実際、そのように一度にすべての試合をキャプチャする必要があることはめったにない。そして、それらすべての中間一致を追跡するために必要なすべてのストレージおよび/または処理能力について考えてください。しかし、それは素晴らしい機能です。

于 2009-12-18T05:40:33.930 に答える