【问题标题】:Parse string using format template?使用格式模板解析字符串?
【发布时间】:2011-03-17 22:39:48
【问题描述】:

如果我可以使用

格式化字符串
string.Format("my {0} template {1} here", 1, 2)

我可以反转这个过程吗?我提供了模板和一个填充的字符串,.net 返回 arg0、arg1 等?

【问题讨论】:

  • 这听起来像是我认为使用正则表达式的一个案例......
  • 我很好奇是否可以避免使用正则表达式。似乎两个对象共享一个模板,并简单地使用该模板填充和取消填充一个字符串。会很优雅。

标签: c# .net string


【解决方案1】:

没有优雅的方式来反转格式化的字符串。但是如果你想要一个简单的功能,你可以试试这个。

private List<string> reverseStringFormat(string template, string str)
{
     //Handles regex special characters.
    template = Regex.Replace(template, @"[\\\^\$\.\|\?\*\+\(\)]", m => "\\" 
     + m.Value);

    string pattern = "^" + Regex.Replace(template, @"\{[0-9]+\}", "(.*?)") + "$";
        
    Regex r = new Regex(pattern);
    Match m = r.Match(str);

    List<string> ret = new List<string>();

    for (int i = 1; i < m.Groups.Count; i++)
    {
        ret.Add(m.Groups[i].Value);
    }

    return ret;
}

【讨论】:

  • 谢谢!希望有一些内置到.net的东西,但似乎没有。这是一个很好的解决方案。
  • 不错的解决方案。为确保生成的模式有效,您必须在创建模式之前替换所有特殊的正则表达式字符:template = Regex.Replace(template, @"[\\\^\$\.\|\?\*\+\(\)]", m =&gt; "\\" + m.Value)
  • @Elian 好电话。另外,应该注意的是,这不会在 Alexei 下面描述的情况下重现正确的结果。
  • 为转义字符添加方括号:template = Regex.Replace(template, @"[\\\^\$\.\|\?\*\+\(\)\[\]]", m =&gt; "\\" + m.Value);
【解决方案2】:

String.Format 在一般情况下是不可逆的。

如果您只有一个 {0},那么实际上可以编写至少提取值的字符串表示形式的通用代码。您绝对不能将其反转以生成原始对象。

样品:

  1. 多个参数:string.Format("my{0}{1}", "aa", "aaa"); 产生“myaaaaa”,要反转 string.ReverseFormat("my{0}{1}", "myaaaaa") 必须决定如何在没有任何信息的情况下将“aaaaa”部分拆分为 2。

  2. 无法反转到数据类型string.Format("{0:yyyy}", DateTime.Now); 导致 2011 年,有关价值本身的大部分信息丢失。

【讨论】:

    【解决方案3】:

    一种方法是使用正则表达式。对于您的示例,您可以这样做:

    Regex regex = new Regex("^my (.*?) template (.*?) here$");
    Match match = regex.Match("my 53 template 22 here");
    string arg0 = match.Groups[1].Value;    // = "53"
    string arg1 = match.Groups[2].Value;    // = "22"
    

    根据这种技术编写一个扩展方法来做你想做的事情并不难。

    只是为了好玩,这是我第一次天真的尝试。我还没有测试过这个,但它应该很接近。

    public static object[] ExtractFormatParameters(this string sourceString, string formatString)
    {
        Regex placeHolderRegex = new Regex(@"\{(\d+)\}");
        Regex formatRegex = new Regex(placeHolderRegex.Replace(formatString, m => "(<" + m.Groups[1].Value + ">.*?)");
        Match match = formatRegex.Match(sourceString);
        if (match.Success)
        {
            var output = new object[match.Groups.Count-1];
            for (int i = 0; i < output.Length; i++)
                output[i] = match.Groups[i+1].Value;
            return output;
        }
        return new object[];
    } 
    

    这将允许您这样做

    object[] args = sourceString.ExtractFormatParameters("my {0} template {1} here");
    

    该方法非常幼稚,存在很多问题,但它基本上会在格式表达式中找到任何占位符,并在源字符串中找到对应的文本。它将为您提供与从左到右列出的占位符相对应的值,而不参考序数或占位符中指定的任何格式。可以添加此功能。

    另一个问题是格式字符串中的任何特殊正则表达式字符都会导致方法失败。需要对formatRegex 进行更多处理以转义属于formatString 的任何特殊字符。

    【讨论】:

    • 您能否确认无法按原样使用字符串模板(无需编写自定义扩展方法)?见上面的 cmets。
    • 我不知道,但这并不意味着什么。但是我可以看到编写一个方法,该方法将采用正确大小的格式和对象数组,解析格式并将其转换为适当的正则表达式,进行匹配,然后用结果值填充对象数组。
    • 是的......就像上面@climbage的解决方案一样。
    【解决方案4】:

    使用正则表达式解析出组匹配。

    Regex.Match("my (.*) template (.*) here", theFilledInString);
    

    我没有打开 VS,所以我无法验证我的方法名称是否正确,但你会明白我的意思。通过使用括号,返回的匹配结果将包含包含您提取的匹配项的 groups[0] 和 groups[1]。

    【讨论】:

    • 有没有办法避免正则表达式? .net 是否具有使用 args 为 {} 格式的模板解析字符串的内置机制?
    • 我没见过这样的东西。我想您可以在处理这些模板时将“{0}”自动替换为“(.*)”。看看上面攀登的答案。
    猜你喜欢
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多