Есть ли лучший способ подсчета заполнителей формата строки в строке в C #? - PullRequest
11 голосов
/ 04 июня 2009

У меня есть строка шаблона и массив параметров, которые поступают из разных источников, но должны быть сопоставлены для создания новой «заполненной» строки:

string templateString = GetTemplate();   // e.g. "Mr {0} has a {1}"
string[] dataItems = GetDataItems();     // e.g. ["Jones", "ceiling cat"}

string resultingString = String.Format(templateString, dataItems);
// e.g. "Mr Jones has a ceiling cat"

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

Если в dataItems слишком много элементов, метод String.Format прекрасно с этим справится. Если их недостаточно, я получаю исключение.

Чтобы преодолеть это, я считаю число заполнителей и добавляю новые элементы в массив dataItems, если их недостаточно.

Для подсчета заполнителей код, с которым я сейчас работаю:

private static int CountOccurrences(string haystack)
{
    // Loop through all instances of the string "}".
    int count = 0;
    int i = 0;
    while ((i = text.IndexOf("}", i)) != -1)
    {
        i++;
        count++;
    }
    return count;
}

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

Есть ли лучший способ подсчета заполнителей формата строки в строке?


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

  • Регулярные выражения, которые подсчитывают количество заполнителей, не учитывают буквенные скобки ({{0}})
  • Подсчет заполнителей не учитывает повторные или пропущенные заполнители (например, "{0} has a {1} which also has a {1}")

Ответы [ 12 ]

0 голосов
/ 31 октября 2017

На основании этого ответа и ответа Дэвида Уайта вот обновленная версия:

string formatString = "Hello {0:C} Bye {{300}} {0,2} {34}";
//string formatString = "Hello";
//string formatString = null;

int n;
var countOfParams = Regex.Matches(formatString?.Replace("{{", "").Replace("}}", "") ?? "", @"\{([0-9]+)")
    .OfType<Match>()
    .DefaultIfEmpty()
    .Max(m => Int32.TryParse(m?.Groups[1]?.Value, out n) ? n : -1 )
    + 1;

Console.Write(countOfParams);

На что обратить внимание:

  1. Замена - это более простой способ позаботиться о двойных фигурных скобках. Это похоже на то, как StringBuilder.AppendFormatHelper заботится о них внутренне.
  2. Как и при удалении '{{' и '}}', регулярное выражение можно упростить до '{([0-9] +)'
  3. Это будет работать, даже если formatString имеет значение null
  4. Это будет работать, даже если есть недопустимый формат, скажем, "{3444444456}". Обычно это вызывает переполнение целых чисел.
0 голосов
/ 04 июня 2009

Вы можете использовать регулярное выражение для подсчета пар {}, которые имеют только форматирование, которое вы используете между ними. @ "\ {\ d + \}" достаточно, если вы не используете параметры форматирования.

...