C#从messageformat字符串中查找特定值

时间:2019-05-29 16:31:28

标签: c# regex string-matching messageformat

给出下面的消息格式字符串,例如file0 file1 。我希望能够获得用于显示文本值的“通知”和“名称”值。

str

我尝试使用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}!";

但是以上内容并未考虑到var matches = Regex.Matches(str, @"{(.*?)}"); //var matches = Regex.Matches(str, @"(?<=\{)[^}{]*(?=\})"); var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct().ToList(); 本身用花括号括起来,并且包括不需要的内部值,这些值也用花括号括起来。

因此,简而言之,我只想能够解析上面的字符串{notifications,..并在返回值处获得strnotifications

诸如name之类的字符串应仅返回var str2 = @"Hello {name}"作为值。

编辑

namenotifications不会预先知道-我仅以此为例,说明了我需要从字符串返回的值。

2 个答案:

答案 0 :(得分: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 Locals窗口复制)

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

...原始答案如下...


关于原始问题中当前解决方案的一件事:

  • 使用.与换行符不匹配,因此这是它当前与嵌套值匹配的原因之一(请参阅此source

如果我了解您的目标,那么这篇文章将很好地说明和演示相关问题和解决方案:

(本文解决了原始问题中提到的主要挑战-嵌套花括号

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 Locals窗口复制)

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

更新

我回到这一点,意识到这个问题只要求单词作为结果。

然后从每个结果中提取第一个单词

(我在上面的代码段中附加了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 Locals窗口复制)

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

更多信息

(我刚刚发现这很有趣,花了一些时间进行研究/学习,并认为它值得包含更多相关信息)

对话herehere包含针对使用正则表达式解决此类问题的一些观点。

  • 我认为阅读这些观点并获得更全面的观点很有趣

不管以上观点如何,.NET创建者都认为实现平衡组定义是适当的-此答案使用的功能是

答案 1 :(得分:0)

执行此操作的一种方法是编写一种方法,该方法将基于输入count和字符串的单数(或复数)形式为您格式化字符串:

private static string FormatWord(int count, string singluar)
{
    return Format(count, singluar, singluar + "s");
}

private static string FormatWord(int count, string singular, string plural)
{
    return count == 0 ? "no " + plural
        : count == 1 ? "one " + singular
        : count == 42 ? "a universal number of " + plural
        : count + " " + plural;
}

然后在使用中它可能看起来像:

private static void Main()
{
    var name = "User";

    while (true)
    {
        var count = GetIntFromUser("Enter notification count: ");
        Console.WriteLine($"You have {FormatWord(count, "notification")}. " + 
            $"Have a nice day, {name}");
    }
}

请注意,该方法还使用了辅助方法来从用户那里获取强类型整数:

private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
    int result;
    var cursorTop = Console.CursorTop;

    do
    {
        ClearSpecificLineAndWrite(cursorTop, prompt);
    } while (!int.TryParse(Console.ReadLine(), out result) ||
             !(validator?.Invoke(result) ?? true));

    return result;
}

private static void ClearSpecificLineAndWrite(int cursorTop, string message)
{
    Console.SetCursorPosition(0, cursorTop);
    Console.Write(new string(' ', Console.WindowWidth));
    Console.SetCursorPosition(0, cursorTop);
    Console.Write(message);
}