7

我们的低级日志库必须处理发送给它的各种日志消息。

其中一些消息包括大括号(作为文本的一部分),一些包含要使用 String.Format 格式化为字符串的一部分的参数

例如,此字符串可以是 Logger 类的输入:

“参数:{Hostname} 值:{0}”发送正确的变量以供格式化程序使用。

为了正确地做到这一点,我必须转义不属于格式的花括号(通过将它们加倍)。

我想过使用正则表达式来做,但这并不像看起来那么简单,因为我不知道如何在花括号内匹配这些字符串(String.Format 不用于格式化目的的字符串)。

另一个问题是 Logger 类应该尽可能提高性能,开始处理正则表达式作为其操作的一部分可能会降低性能。

是否有任何适当且已知的最佳实践?

4

4 回答 4

4

只需一个正则表达式即可:

string input = "Parameter: {Hostname} Value: {0}";
input = Regex.Replace(input, @"{([^[0-9]+)}", @"{{$1}}");
Console.WriteLine(input);

输出:

参数:{{Hostname}} 值:{0}

这当然只适用于没有任何包含数字但仍应转义的参数{{ }}

于 2011-11-15T08:31:37.643 回答
2

我会把所有的花括号加倍,然后我会寻找那些用正则表达式替换,{{\d+}}这样它们就会在你的字符串中恢复到原来的格式——{{0}} => {0}。
所以对于每一行我都会这样做

string s = input.Replace("{", "{{").Replace("}", "}}");
return Regex.Replace(s, @"{{(?<val>\d+)}}", 
                     m => { return "{" + m.Groups["val"] + "}"; }));

所以这是对原始问题的技术答案,但@Anders Abel 是完全正确的。值得再次考虑设计...

于 2011-11-15T08:08:04.533 回答
2

我认为您应该查看您的记录器界面。与Console.WriteLine工作方式比较:

  • Console.WriteLine(String)准确输出给定的字符串,没有格式,{ 和 } 没什么特别的。
  • Console.WriteLine(String, Object[])使用格式化输出。{ 和 } 是调用者必须转义到 {{ 和 }} 的特殊字符

我认为这是有缺陷的设计,必须区分代码中不同的大括号出现以找出其含义。将输出中应该出现的 { 转义的负担放到 {{ 中。

于 2011-11-15T08:12:44.843 回答
2

允许调用者拥有格式化的字符串并处理格式化说明符,例如

Logger.Log("{0:dd/mm/yyy} {0:hh:mm:ss} {hostname} {123Component} 发生了一些错误 {1:x4}!", DateTime.UtcNow, 257)

你需要一个像这样的正则表达式:

string input = "{0:dd/mm/yyy} {0:hh:mm:ss} {hostname} Some error {1:x4} happened on {123Component}!";
Regex reg = new Regex(@"(\{[^[0-9}]+?[^}]*\}|\{(?![0-9]+:)[^}]+?\})");
string output = reg.Replace(input, "{$1}");
Console.WriteLine(output);

这输出:

"{0:dd/mm/yyy} {0:hh:mm:ss} {{hostname}} Some error {1:x4} happened on {{123Component}}!"

但重申一下,我同意 Anders Abel 的观点,即您应该重新设计以避免日志库需要这样做。

于 2011-11-15T09:16:35.643 回答