Разобрать строку используя шаблон формата? - PullRequest
19 голосов
/ 18 марта 2011

Если я могу отформатировать строку, используя

string.Format("my {0} template {1} here", 1, 2)

, могу ли я изменить процесс - я предоставляю шаблон и заполненную строку, .net возвращает arg0, arg1 и т. Д.

Ответы [ 4 ]

30 голосов
/ 18 марта 2011

Нет элегантного способа перевернуть отформатированную строку. Но вы можете попробовать это, если хотите простую функцию.

private List<string> reverseStringFormat(string template, string str)
{
     //Handels 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;
}
7 голосов
/ 18 марта 2011

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 года, большая часть информации о самом значении потеряна.

2 голосов
/ 18 марта 2011

Используйте регулярные выражения для разбора совпадений групп.

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

У меня нет открытого VS, поэтому я не могу проверить, правильно ли я назвал метод, но вы будете знать, чтоимею в виду.При использовании парантеза возвращенный результат совпадения будет иметь группы [0] и группы [1], содержащие ваши извлеченные совпадения.

2 голосов
/ 18 марта 2011

Один из способов сделать это - регулярные выражения.Для вашего примера вы могли бы сделать:

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.

...