String.Format с фигурными скобками - PullRequest
6 голосов
/ 15 ноября 2011

Наша низкоуровневая библиотека журналов справляется со всеми видами сообщений журнала, отправляемых ей.

Некоторые из этих сообщений содержат фигурные скобки (как часть текста), а некоторые содержат параметры, которые должны быть отформатированы какчасть строки с использованием String.Format

Например, эта строка может быть входом для класса Logger:

"Параметр: {Имя хоста} Значение: {0}" С правильной переменнойотправлено на использование для форматера.

Чтобы правильно это сделать, я должен убрать фигурные скобки, которые не являются частью форматирования (удвоив их).

Я думал о том, чтобы сделатьон использует Regex, однако это не так просто, как может показаться, поскольку я понятия не имею, как сопоставить эти строки внутри фигурных скобок (те, которые НЕ используются String.Format для форматирования).

Другая проблема заключается в том, что класс Logger должен быть максимально эффективным с точки зрения производительности, начиная с обработки регулярных выражений, поскольку часть его работы может снижать производительность.

Is thЕсть ли подходящая и известная лучшая практика для этого?

Ответы [ 4 ]

3 голосов
/ 15 ноября 2011

Выполнение всего за одно регулярное выражение:

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

Выходы:

Параметр: {{Hostname}} Значение: {0}

Это, конечно, работает только до тех пор, пока нет параметров, которые содержат числа, но по-прежнему должны быть экранированы с помощью {{ }}

2 голосов
/ 15 ноября 2011

Чтобы разрешить вызывающей стороне отформатировать строки и справиться с передаваемыми спецификаторами, например,

Logger.Log ("{0: дд / мм / ггг} {0: чч: мм: сс} {имя хоста} Произошла ошибка {1: x4} в {123Component}!", 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}}!"

Но, повторюсь, я бы согласился с Андерсом Абелем, что вам следует изменить дизайн, чтобы избежать необходимости в библиотеке журналов для этого.

2 голосов
/ 15 ноября 2011

Я думаю, что вы должны заглянуть в интерфейс вашего логгера. Сравните с тем, как работает Console.WriteLine:

  • Console.WriteLine(String) выводит именно заданную строку, без форматирования, ничего особенного с {и}.
  • Console.WriteLine(String, Object[]) вывод с использованием форматирования. {и} являются специальными символами, в которые вызывающая сторона должна переходить на {{и}}

Я думаю, что это неправильный дизайн, когда нужно различать в коде различные фигурные скобки, чтобы выяснить, что имеется в виду. Возложите бремя спасения {которое должно произойти на выходе в {{.

2 голосов
/ 15 ноября 2011

Я бы удвоил все фигурные скобки, а затем я бы искал те, которые должны быть заменены регулярным выражением типа {{\d+}}, чтобы они вернулись к своему первоначальному формату - {{0}} => {0} - в вашей строке.
Так что для каждой строки я бы сделал что-то вроде этого

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

Так что это технический ответ на оригинальный вопрос, но @Anders Abel совершенно прав. Стоит еще раз рассмотреть дизайн ...

...