0

以下のようなメッセージフォーマット文字列が与えられstrます。テキスト値の表示に使用される「通知」と「名前」の値を取得できるようにしたいと考えています。

var str = @"You have {notifications, plural,
          zero {no notifications}
           one {one notification}
           =42 {a universal amount of notifications}
         other {# notifications}
        }. Have a nice day, {name}!";

次のような正規表現を使用してみました。

var matches = Regex.Matches(str, @"{(.*?)}");
//var matches = Regex.Matches(str, @"(?<=\{)[^}{]*(?=\})");
var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct().ToList();

ただし、上記は、それ自体が中括弧で囲まれていることを考慮しておらず{notifications,..、中括弧で囲まれている不要な内部値を含んでいます。

簡単に言えば、str上記のような文字列を解析し、返された値でnotifications&を取得できるようにしたいだけです。name

のような文字列は、値としてvar str2 = @"Hello {name}"返されるだけnameです。

編集

notifications&の値nameは事前にわかりません。これは、文字列から返す必要がある値の例として使用しただけです。

4

2 に答える 2

1

TL;DR: これはオプションのソリューションです

var str = @"You have {notifications, plural,
          zero {no notifications}
           one {one notification}
           =42 {a universal amount of notifications}
         other {# notifications}
        }. Have a nice day, {name}!";

// get matches skipping nested curly braces
var matches = 
    Regex.Matches(str, @"{((?:[^{}]|(?<counter>{)|(?<-counter>}))+(?(counter)(?!)))}");

var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct()
    .Select(v => Regex.Match(v, @"^\w+").Value) // take 1st word
    .ToList();

その結果(デバッグ中にVisual Studioローカルウィンドウからコピー)

results Count = 2   System.Collections.Generic.List<string>
    [0] "notifications"
    [1] "name"

...元の答えは続きます...


元の質問の現在の解決策について注意すべき点が 1 つあります。

  • の使用は.改行と一致しないため、現在ネストされた値と一致する理由の 1 つです (このソースを参照)

あなたの目標を理解できれば、この記事は関連する問題と解決策の素晴らしい説明とデモンストレーションです。

(この記事では、元の質問で指摘された主な課題、つまりネストされた中括弧について説明します)

https://blogs.msdn.microsoft.com/timart/2013/05/14/nestedrecursive-regex-and-net-balancing-groups-detect-a-function-with-a-regex/

その記事から、オプションの解決策として以下のパターンを提案します。

var str = @"You have {notifications, plural,
          zero {no notifications}
           one {one notification}
           =42 {a universal amount of notifications}
         other {# notifications}
        }. Have a nice day, {name}!";

// get matches skipping nested curly braces
var matches = 
    Regex.Matches(str, @"{((?:[^{}]|(?<counter>{)|(?<-counter>}))+(?(counter)(?!)))}");
var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct().ToList();

その結果(デバッグ中にVisual Studioローカルウィンドウからコピー)

results Count = 2   System.Collections.Generic.List<string>
    [0] "notifications, plural,\r\n          zero {no notifications}\r\n           one {one notification}\r\n           =42 {a universal amount of notifications}\r\n         other {# notifications}\r\n        "
    [1] "name"

(または、これらの結果をコンソールに出力する場合):

// Result 0 would look like:
notifications, plural,
          zero {no notifications}
           one {one notification}
           =42 {a universal amount of notifications}
         other {# notifications}


// Result 1 would look like:
name

アップデート

私はこれに戻って、質問が結果として単語を 1 つだけ要求していることに気付きました。

次に、各結果から最初の単語を取得します

(完全な解決策を示すために、追加の select ステートメントを使用して上記のスニペットを繰り返しています)

var str = @"You have {notifications, plural,
          zero {no notifications}
           one {one notification}
           =42 {a universal amount of notifications}
         other {# notifications}
        }. Have a nice day, {name}!";

// get matches skipping nested curly braces
var matches = 
    Regex.Matches(str, @"{((?:[^{}]|(?<counter>{)|(?<-counter>}))+(?(counter)(?!)))}");

var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct()
    .Select(v => Regex.Match(v, @"^\w+").Value) // take 1st word
    .ToList();

その結果(デバッグ中にVisual Studioローカルウィンドウからコピー)

results Count = 2   System.Collections.Generic.List<string>
    [0] "notifications"
    [1] "name"

もう少し情報

(私はこれが興味深いと感じ、調査/学習にもう少し時間を費やし、さらに関連情報を含める価値があると考えました)

ここここでの会話には、この種の問題に正規表現を使用することに賛成または反対する意見が含まれています。

  • これらの意見を読んで、よりバランスの取れた視点を得ることは興味深いと思います

上記の意見に関係なく、.NET の作成者は、バランス グループ定義を実装することが適切であると考えました。これは、この回答が使用する機能です。

于 2019-05-29T18:42:48.320 に答える