Мне нужно найти строку и заменить все вхождения %FirstName%
и %PolicyAmount%
значение извлекается из базы данных. Проблема в том, что заглавные буквы FirstName меняются. Это мешает мне использовать String.Replace()
метод. Я видел веб-страницы на эту тему, которые предлагают
Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);
Однако по какой-то причине, когда я пытаюсь заменить %PolicyAmount%
на $0
, замена никогда не происходит. Я предполагаю, что это как-то связано с тем, что знак доллара является зарезервированным символом в регулярном выражении.
Есть ли другой метод, который я могу использовать, который не включает в себя очистку ввода для работы со специальными символами регулярного выражения?
Ответы:
От MSDN
$ 0 - «Подставляет последнюю подстроку, соответствующую номеру группы (десятичному)».
В .NET Регулярные выражения группа 0 - это всегда полное совпадение. Для буквального $ вам нужно
источник
Похоже,
string.Replace
должен иметь перегрузку, которая принимаетStringComparison
аргумент. Поскольку это не так, вы можете попробовать что-то вроде этого:источник
ReplaceString
наReplace
.oldValue == newValue == ""
.ReplaceString("œ", "oe", "", StringComparison.InvariantCulture)
броскиArgumentOutOfRangeException
.Вид запутанной группы ответов, отчасти потому, что название вопроса на самом деле намного больше, чем конкретный вопрос, который задают. После прочтения, я не уверен, что какой-либо ответ будет в нескольких редакциях от усвоения всех хороших вещей здесь, поэтому я решил, что постараюсь подвести итог.
Вот метод расширения, который, я думаю, позволяет избежать ловушек, упомянутых здесь, и обеспечивает наиболее широкое применение.
Так...
"œ".ReplaceCaseInsensitiveFind("oe", "")
хотя он , возможно, имели различное поведение в виду.К сожалению, комментарий @HA о том, что у вас есть
Escape
все три , неверен . Начальное значение иnewValue
не должно быть.Примечание: вы, однако, должны экранировать
$
s в новом значении, которое вы вставляете, если они являются частью того, что может показаться маркером «захваченного значения» . Таким образом, три знака доллара в Regex.Replace внутри Regex.Replace [sic]. Без этого что-то подобное ломается ..."This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")
Вот ошибка:
Скажу вам, что, я знаю, что люди, которым удобно с Regex, чувствуют, что их использование позволяет избежать ошибок, но я часто все еще неравнодушен к анализу байтовых строк (но только после прочтения Spolsky в кодировках ), чтобы быть абсолютно уверенным, что вы получаете то, что вы предназначен для важных случаев использования. Немного напоминает мне Крокфорда о « небезопасных регулярных выражениях ». Слишком часто мы пишем
$10
регулярные выражения, которые разрешают то, что мы хотим (если нам повезет), но непреднамеренно допускают больше в (например, действительно ли является допустимой строкой «значения захвата» в моем регулярном выражении newValue, выше?), Потому что мы не были достаточно вдумчивыми , Оба метода имеют ценность, и оба поощряют различные типы непреднамеренных ошибок. Часто легко недооценить сложность.Это странное
$
побег (и этоRegex.Escape
не ускользнуло от шаблонов захваченных значений, таких$0
как, как я ожидал бы от значений замещения), на какое-то время сводило меня с ума. Программирование сложно (с) 1842источник
Вот метод расширения. Не уверен, где я нашел это.
источник
Кажется, самый простой способ - это просто использовать метод Replace, который поставляется с .Net и существует с .Net 1.0:
Чтобы использовать этот метод, необходимо добавить ссылку на сборку Microsoft.VisualBasic. Эта сборка является стандартной частью среды выполнения .Net, она не является дополнительной загрузкой или помечена как устаревшая.
источник
C. Dragon 76
сработал, как и ожидалось.источник
Вдохновленный ответом cfeduke, я создал эту функцию, которая использует IndexOf для поиска старого значения в строке и затем заменяет его новым значением. Я использовал это в скрипте SSIS, обрабатывающем миллионы строк, и метод регулярных выражений был намного медленнее, чем этот.
источник
Расширяем популярный ответ C. Dragon 76 , превращая его код в расширение, перегружающее
Replace
метод по умолчанию .источник
На основании ответа Джеффа Редди, с некоторыми оптимизациями и проверками:
источник
версия, аналогичная версии C. Dragon, но если вам нужна только одна замена:
источник
Вот еще один вариант выполнения замен Regex, так как не многие люди замечают, что совпадения содержат расположение в строке:
источник
источник
Метод регулярного выражения должен работать. Однако то, что вы также можете сделать, это нижний регистр строки из базы данных, нижний регистр% переменных%, который у вас есть, а затем найти позиции и длины в строчной строке из базы данных. Помните, что позиции в строке не меняются только потому, что ее нижний регистр.
Затем, используя цикл, который идет в обратном порядке (проще, если вы этого не сделаете, вам придется вести счетчик количества движений, в которые перемещаются более поздние точки), удалить из вашей строки без нижестоящего регистра из базы данных% variable% по их положению и длина и вставить значения замены.
источник
(Так как все это делают). Вот моя версия (с нулевыми проверками и корректным выходом и заменой при выходе) ** Вдохновленные из Интернета и других версий:
Использование:
источник
Позвольте мне сделать мое дело, и тогда вы можете разорвать меня на куски, если хотите.
Regex не является ответом на эту проблему - слишком медленно и требует много памяти, условно говоря.
StringBuilder намного лучше, чем искажение строк.
Поскольку это будет дополнительный метод расширения
string.Replace
, я считаю, что важно соответствовать тому, как это работает, поэтому важно создавать исключения для тех же проблем с аргументами, как и возврат исходной строки, если замена не была сделана.Я считаю, что наличие параметра StringComparison не очень хорошая идея. Я попробовал, но тестовый пример, упомянутый Майклом Лю, показал проблему:
Хотя IndexOf будет совпадать, существует несоответствие между длиной совпадения в исходной строке (1) и oldValue.Length (2). Это проявилось в появлении IndexOutOfRange в некоторых других решениях, когда oldValue.Length был добавлен к текущей позиции совпадения, и я не смог найти способ обойти это. В любом случае, Regex не подходит к этому случаю, поэтому я выбрал прагматичное решение - использовать только
StringComparison.OrdinalIgnoreCase
мое решение.Мой код похож на другие ответы, но мой поворот в том, что я ищу совпадение, прежде чем приступить к созданию
StringBuilder
. Если ничего не найдено, то возможно избежать большого распределения. Код становитсяdo{...}while
скорее, чемwhile{...}
Я провел обширное тестирование против других Ответов, и оно получилось немного быстрее и заняло немного меньше памяти.
источник