У меня есть большой текстовый шаблон, в котором нужно заменить токенизированные разделы другим текстом. Жетоны выглядят примерно так: ## ИМЯ ПОЛЬЗОВАТЕЛЯ ##. Мой первый инстинкт - просто использовать String.Replace (), но есть ли лучший и более эффективный способ или Replace () уже оптимизирован для этого?





System.Text.RegularExpressions.Regex.Replace () - это то, что вы ищете - ЕСЛИ ваши токены достаточно странные, чтобы их найти, вам понадобится регулярное выражение.
Какая-то добрая душа провела тестирование производительности, и между Regex.Replace (), String.Replace () и StringBuilder.Replace (), String.Replace () фактически вышла на первое место.
RegEx - ужасный вариант для выполнения замены большого количества текста. Каким бы мощным он ни был, многие сторонники RegEx видят весь мир как гвоздь, а RegEx - как молоток. Для случаев использования большого количества текста см. FastReplacer stackoverflow.com/a/11442008/141172.
string.Replace в порядке. Я бы предпочел использовать Regex, но я *** для регулярных выражений.
Следует иметь в виду, насколько велики эти шаблоны. Если он действительно большой, а память является проблемой, вы можете создать собственный токенизатор, который действует в потоке. Таким образом, вы удерживаете в памяти только небольшую часть файла, пока вы работаете с ним.
Но для наивной реализации string.Replace подойдет.
Если вы выполняете множественные замены для больших строк, возможно, лучше использовать StringBuilder.Replace (), поскольку появятся обычные проблемы с производительностью со строками.
Пришлось сделать что-то подобное недавно. Что я сделал:
Выполнено ;-)
Если вы хотите протестировать свои регулярные выражения, я могу предложить регулятор.
Это идеальное использование регулярных выражений. Посмотрите этот полезный сайт, .Net Класс регулярных выражений и эту очень полезную книгу Освоение регулярных выражений.
Единственная ситуация, в которой мне пришлось это сделать, - это отправить шаблонное электронное письмо. В .NET это предусмотрено MailDefinition класс. Итак, вот как вы создаете шаблонное сообщение:
MailDefinition md = new MailDefinition();
md.BodyFileName = pathToTemplate;
md.From = "[email protected]";
ListDictionary replacements = new ListDictionary();
replacements.Add("<%To%>", someValue);
// continue adding replacements
MailMessage msg = md.CreateMailMessage("[email protected]", replacements, this);
После этого будет создан msg.Body путем подстановки значений в шаблоне. Думаю, вы можете взглянуть на MailDefinition.CreateMailMessage () с помощью Reflector :). Извините за то, что немного не по теме, но если это ваш сценарий, я думаю, что это самый простой способ.
Регулярные выражения были бы самым быстрым решением для кодирования, но если у вас много разных токенов, он будет работать медленнее. Если производительность не является проблемой, используйте эту опцию.
Лучшим подходом было бы определение токена, например вашего "##", который вы можете сканировать в тексте. Затем выберите из хэш-таблицы, что нужно заменить, с текстом, который следует за токеном в качестве ключа.
Если это часть сценария сборки, то у nAnt есть отличная функция для этого, называемая Цепочки фильтров. Код для этого имеет открытый исходный код, поэтому вы можете посмотреть, как это делается для быстрой реализации.
Что ж, в зависимости от того, сколько переменных у вас есть в вашем шаблоне, сколько у вас есть шаблонов и т. д., Это может быть работой для полного процессора шаблонов. Единственный, который я когда-либо использовал для .NET, - это NVelocity, но я уверен, что там должно быть множество других, большинство из которых связаны с той или иной веб-структурой.
Если ваш шаблон большой и у вас много токенов, вы, вероятно, не захотите обходить его и заменять токен в шаблоне один за другим, так как это приведет к операции O (N * M), где N - размер шаблон, а M - количество заменяемых токенов.
Следующий метод принимает шаблон и словарь пар ключей и значений, которые вы хотите заменить. Инициализация StringBuilder чуть больше размера шаблона должна привести к операции O (N) (т.е. он не должен увеличиваться в журнал N раз).
Наконец, вы можете переместить сборку токенов в синглтон, поскольку его нужно сгенерировать только один раз.
static string SimpleTemplate(string template, Dictionary<string, string> replacements)
{
// parse the message into an array of tokens
Regex regex = new Regex("(##[^#]+##)");
string[] tokens = regex.Split(template);
// the new message from the tokens
var sb = new StringBuilder((int)((double)template.Length * 1.1));
foreach (string token in tokens)
sb.Append(replacements.ContainsKey(token) ? replacements[token] : token);
return sb.ToString();
}
FastReplacer реализует замену токена за время O (n * log (n) + m) и использует в 3 раза больше памяти исходной строки.
FastReplacer is good for executing many Replace operations on a large string when performance is important.
The main idea is to avoid modifying existing text or allocating new memory every time a string is replaced.
We have designed FastReplacer to help us on a project where we had to generate a large text with a large number of append and replace operations. The first version of the application took 20 seconds to generate the text using StringBuilder. The second improved version that used the String class took 10 seconds. Then we implemented FastReplacer and the duration dropped to 0.1 seconds.
Это то, что я искал. Пожалуйста, проверьте таблицу скорости и попробуйте.
Я считаю, что они провели свой тест в PowerShell, что не относится к C#. В C3 управление памятью отличается от PowerShell, и он не преобразует StringBuilder в String для замены в нем символов. С другой стороны, RegEx и StringBuilder лучше работают с большими объемами данных, которые добавляются к ним кусками.