【问题标题】:C# Named parameters to a string that replace to the parameter valuesC# 将参数命名为替换为参数值的字符串
【发布时间】:2010-09-27 14:49:41
【问题描述】:

我希望以一种良好的性能方式(我希望)将我的字符串中的命名参数替换为代码中的命名参数,例如我的字符串:

"Hi {name}, do you like milk?"

如何用代码、正则表达式替换 {name}?贵吗?你推荐哪种方式?

他们如何在示例 NHibernates HQL 中将 :my_param 替换为用户定义的值?或者在我更喜欢的 ASP.NET (MVC) 路由中,"{controller}/{action}", new { controller = "Hello", ... }?

【问题讨论】:

    标签: c# regex performance string named-parameters


    【解决方案1】:

    我会选择 mindplay.dk 解决方案...效果很好。

    而且,稍作修改,它支持模板的模板,如 “嗨,{name},你喜欢 {0}?”,替换 {name} 但保留 {0}:

    在给定的源(https://gist.github.com/896724)中,替换如下:

            var format = Pattern.Replace(
                template,
                match =>
                    {
                        var name = match.Groups[1].Captures[0].Value;
    
                        if (!int.TryParse(name, out parsedInt))
                        {
                            if (!map.ContainsKey(name))
                            {
                                map[name] = map.Count;
                                list.Add(dictionary.ContainsKey(name) ? dictionary[name] : null);
                            }
    
                            return "{" + map[name] + match.Groups[2].Captures[0].Value + "}";
                        }
                        else return "{{" + name + "}}";
                    }
                );
    

    此外,它支持长度 ({name,30}) 以及格式说明符,或两者的组合。

    【讨论】:

      【解决方案2】:

      如果您将所有替换值都存储在 Dictionary obj 中,请尝试使用 Linq。

      例如:

      Dictionary<string,string> dict = new Dictionary<string,string>();
      dict.add("replace1","newVal1");
      dict.add("replace2","newVal2");
      dict.add("replace3","newVal3");
      
      var newstr = dict.Aggregate(str, (current, value) => current.Replace(value.Key, value.Value));
      

      dict 是您定义的搜索替换对字典对象。 str 是您需要进行一些替换的字符串。

      【讨论】:

        【解决方案3】:

        考虑到这一点,我意识到我真正希望的是,String.Format() 将 IDictionary 作为参数,并且模板可以使用名称而不是索引来编写。

        对于具有许多可能的键/值的字符串替换,索引号会导致难以辨认的字符串模板 - 在某些情况下,您甚至可能不知道哪些项目将有什么数字,所以我想出了以下扩展名:

        https://gist.github.com/896724

        基本上,这使您可以使用带有名称而不是数字的字符串模板,以及带有字典而不是数组的字符串模板,并让您拥有 String.Format() 的所有其他良好功能,如果需要,可以使用自定义 IFormatProvider , 并允许使用所有常用的格式化语法 - 精度、长度等。

        String.Format 参考资料中提供的example 是一个很好的例子,说明带有许多编号项目的模板如何变得完全难以辨认 - 将该示例移植到使用这种新的扩展方法,您会得到如下内容:

        var replacements = new Dictionary<String, object>()
                               {
                                   { "date1", new DateTime(2009, 7, 1) },
                                   { "hiTime", new TimeSpan(14, 17, 32) },
                                   { "hiTemp", 62.1m },
                                   { "loTime", new TimeSpan(3, 16, 10) },
                                   { "loTemp", 54.8m }
                               };
        
        var template =
            "Temperature on {date1:d}:\n{hiTime,11}: {hiTemp} degrees (hi)\n{loTime,11}: {loTemp} degrees (lo)";
        
        var result = template.Subtitute(replacements);
        

        正如有人指出的那样,如果您正在编写的内容需要高度优化,请不要使用这样的东西 - 如果您必须以这种方式格式化数百万个字符串,在一个循环中,内存和性能开销可能是意义重大。

        另一方面,如果您关心编写清晰、可维护的代码 - 并且如果您正在执行一系列数据库操作,从总体上看,此功能不会增加任何重大开销.

        ...

        为方便起见,我确实尝试添加一个可以接受匿名对象而不是字典的方法:

        public static String Substitute(this String template, object obj)
        {
            return Substitute(
                template,
                obj.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(obj, null))
            );
        }
        

        由于某种原因,这不起作用 - 将像 new { name: "value" } 这样的匿名对象传递给该扩展方法会给出编译时错误消息,指出最佳匹配是该方法的 IDictionary 版本。不知道如何解决。 (有人吗?)

        【讨论】:

        • 你有没有想过这个匿名类型?那真的很酷。
        • 我不记得了——那是很久以前的事了,我目前不使用 ASP.NET...我查看了当时的代码,然后它就投入生产了同样——我隐约记得问题不是出在这段代码上,而是出在消费者代码上。这是我能给你的最好的线索。
        【解决方案4】:

        怎么样

        stringVar = "Hello, {0}. How are you doing?";
        arg1 = "John";    // or args[0]
        String.Format(stringVar, arg1)
        

        您甚至可以有多个参数,只需增加 {x} 并将另一个参数添加到 Format() 方法。不确定不同,但“字符串”和“字符串”都有这种方法。

        【讨论】:

        • 他需要命名参数,而不是有序参数。
        【解决方案5】:

        尝试使用 StringTemplate。它比这更强大,但它完美地完成了这项工作。

        【讨论】:

          【解决方案6】:

          你确认正则表达式太贵了吗?

          正则表达式的成本被大大夸大了。对于这样一个简单的模式,性能将非常好,实际上可能只比直接搜索和替换稍差。另外,您在构造正则表达式时是否尝试过Compiled 标志?

          也就是说,你不能用最简单的方法,即Replace吗?

          string varname = "name";
          string pattern = "{" + varname + "}";
          Console.WriteLine("Hi {name}".Replace(pattern, "Mike"));
          

          【讨论】:

          • (虽然你的意思是替换(pattern, "Mike"))
          • @Jon:谢谢。既然有 Jon,为什么还要使用编译器? ;-)
          【解决方案7】:

          现在,如果您在字典中有替换项,如下所示:

              var  replacements = new Dictionary<string, string>();
              replacements["name"] = "Mike";
              replacements["age"]= "20";
          

          然后正则表达式变得非常简单:

          Regex regex = new Regex(@"\{(?<key>\w+)\}");
              string formattext = "{name} is {age} years old";
              string newStr = regex.Replace(formattext, 
                      match=>replacements[match.Groups[1].Captures[0].Value]);
          

          【讨论】:

          • +1 为简洁起见 - 在所有贡献的解决方案中,这是我个人最喜欢的 :-)
          • 讨厌正则表达式,但这很好。
          【解决方案8】:

          正则表达式当然是一个可行的选择,尤其是MatchEvaluator

              Regex re = new Regex(@"\{(\w*?)\}", RegexOptions.Compiled); // store this...
          
              string input = "Hi {name}, do you like {food}?";
          
              Dictionary<string, string> vals = new Dictionary<string, string>();
              vals.Add("name", "Fred");
              vals.Add("food", "milk");
          
              string q = re.Replace(input, delegate(Match match)
              {
                  string key = match.Groups[1].Value;
                  return vals[key];
              });
          

          【讨论】:

          • 该死的......你怎么比我早了 18 分钟?
          • 如果您使用的是 .NET 3.5,则可以取消委托关键字。委托(匹配匹配)可以匹配 =>
          • @scalvert - 确切地说,是 C# 3.0,而不是 .NET 3.5;它也适用于使用 C# 3.0 的 .NET 2.0。
          【解决方案9】:

          编译的正则表达式可能会解决问题,尤其是在要替换许多标记的情况下。如果只有少数几个并且性能是关键,我会简单地通过索引找到令牌并使用字符串函数替换。信不信由你,这将比正则表达式更快。

          【讨论】:

            猜你喜欢
            • 2022-11-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-30
            • 2021-05-23
            • 1970-01-01
            • 1970-01-01
            • 2015-12-26
            相关资源
            最近更新 更多