Есть ли альтернатива string.Replace, которая не чувствительна к регистру?
Мне нужно найти строку и заменить все вхождения %FirstName%
и %PolicyAmount%
значением, вытащенным из базы данных. Проблема в том, что капитализация FirstName меняется. Это мешает мне использовать метод String.Replace()
. Я видел веб-страницы по этому вопросу, которые предлагают
Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);
Однако по какой-то причине, когда я пытаюсь заменить %PolicyAmount%
на $0
, замена никогда не происходит. Я предполагаю, что это имеет какое-то отношение к знаку доллара, который является зарезервированным персонажем в регулярном выражении.
Есть ли другой способ, который я могу использовать, который не предусматривает дезинфекцию ввода для обработки специальных символов регулярного выражения?
Ответы
Ответ 1
Из MSDN
$ 0 - "Заменяет последнюю подстроку, соответствующую номеру группы (десятичный)."
В .NET Группа регулярных выражений 0 всегда совпадает со всем. Для буквального $вам нужно
string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase);
Ответ 2
Кажется, что string.Replace должен иметь перегрузку, которая принимает аргумент StringComparison. Так как это не так, вы можете попробовать что-то вроде этого:
public static string ReplaceString(string str, string oldValue, string newValue, StringComparison comparison)
{
StringBuilder sb = new StringBuilder();
int previousIndex = 0;
int index = str.IndexOf(oldValue, comparison);
while (index != -1)
{
sb.Append(str.Substring(previousIndex, index - previousIndex));
sb.Append(newValue);
index += oldValue.Length;
previousIndex = index;
index = str.IndexOf(oldValue, index, comparison);
}
sb.Append(str.Substring(previousIndex));
return sb.ToString();
}
Ответ 3
Кажется, самый простой способ - просто использовать метод Replace, который поставляется с .Net и существует с .Net 1.0:
string res = Microsoft.VisualBasic.Strings.Replace(res,
"%PolicyAmount%",
"$0",
Compare: Microsoft.VisualBasic.CompareMethod.Text);
Чтобы использовать этот метод, вы должны добавить ссылку на сборку Microsoft.VisualBasic. Эта сборка является стандартной частью среды исполнения .Net, она не является дополнительной загрузкой или помечена как устаревшая.
Ответ 4
Здесь используется метод расширения. Не знаю, где я его нашел.
public static class StringExtensions
{
public static string Replace(this string originalString, string oldValue, string newValue, StringComparison comparisonType)
{
int startIndex = 0;
while (true)
{
startIndex = originalString.IndexOf(oldValue, startIndex, comparisonType);
if (startIndex == -1)
break;
originalString = originalString.Substring(0, startIndex) + newValue + originalString.Substring(startIndex + oldValue.Length);
startIndex += newValue.Length;
}
return originalString;
}
}
Ответ 5
Вид сложной группы ответов, отчасти потому, что название вопроса на самом деле намного больше, чем заданный конкретный вопрос. После прочтения, я не уверен, что какой-либо ответ - это несколько изменений от ассимиляции всех хороших вещей здесь, поэтому я решил, что попытаюсь суммировать.
Здесь метод расширения, который, как я думаю, позволяет избежать описанных здесь ошибок и предоставляет наиболее широко применимое решение.
public static string ReplaceCaseInsensitiveFind(this string str, string findMe,
string newValue)
{
return Regex.Replace(str,
Regex.Escape(findMe),
Regex.Replace(newValue, "\\$[0-9]+", @"$$$0"),
RegexOptions.IgnoreCase);
}
Итак...
К сожалению, @HA комментарий, что вы должны Escape
все три неверны. Начальное значение и newValue
не обязательно.
Примечание. Однако вам нужно избежать $
в новом значении, которое вы вставляете , если они являются частью того, что кажется "зафиксированным значением" "маркер. Таким образом, три знака доллара в Regex.Replace внутри Regex.Replace [sic]. Без этого что-то вроде этого ломается...
"This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")
Здесь ошибка:
An unhandled exception of type 'System.ArgumentException' occurred in System.dll
Additional information: parsing "The\hisr\ is\ he\HISr\ fork,\ he\hIsr\ spoon,\ he\hisrsssssss\ knife\." - Unrecognized escape sequence \h.
Расскажите, что, я знаю, что люди, которым удобно с Regex, чувствуют, что их использование позволяет избежать ошибок, но я часто все еще неравнодушен к байтовым нюхательным строкам (но только после того, как прочитал Spolsky on encodings), чтобы быть абсолютно уверенным, что вы получаете то, что вы предназначили для важных случаев использования. Напоминает мне о Крокфорде "небезопасные регулярные выражения ". Слишком часто мы пишем регулярные выражения, которые позволяют то, что мы хотим (если нам повезет), но непреднамеренно разрешить больше (например, Is $10
действительно допустимая строка "значение захвата" в моем новом regexp newValue выше?), Потому что мы weren ' достаточно задумчивый. Оба метода имеют ценность, и оба поощряют различные типы непреднамеренных ошибок. Часто бывает трудно недооценить сложность.
Это странное $
экранирование (и что Regex.Escape
не удалось избежать захваченных шаблонов значений, таких как $0
, как я ожидал в значениях замещения) некоторое время меня раздражало. Программирование жестко (c) 1842
Ответ 6
/// <summary>
/// A case insenstive replace function.
/// </summary>
/// <param name="originalString">The string to examine.(HayStack)</param>
/// <param name="oldValue">The value to replace.(Needle)</param>
/// <param name="newValue">The new value to be inserted</param>
/// <returns>A string</returns>
public static string CaseInsenstiveReplace(string originalString, string oldValue, string newValue)
{
Regex regEx = new Regex(oldValue,
RegexOptions.IgnoreCase | RegexOptions.Multiline);
return regEx.Replace(originalString, newValue);
}
Ответ 7
Вдохновленный cfeduke ответом, я сделал эту функцию, которая использует IndexOf для поиска старого значения в строке и затем заменяет его новым значением. Я использовал это в SSIS script, обрабатывая миллионы строк, а метод regex был медленнее, чем это.
public static string ReplaceCaseInsensitive(this string str, string oldValue, string newValue)
{
int prevPos = 0;
string retval = str;
// find the first occurence of oldValue
int pos = retval.IndexOf(oldValue, StringComparison.InvariantCultureIgnoreCase);
while (pos > -1)
{
// remove oldValue from the string
retval = retval.Remove(pos, oldValue.Length);
// insert newValue in it place
retval = retval.Insert(pos, newValue);
// check if oldValue is found further down
prevPos = pos + newValue.Length;
pos = retval.IndexOf(oldValue, prevPos, StringComparison.InvariantCultureIgnoreCase);
}
return retval;
}
Ответ 8
Расширение на C. Dragon 76 популярный ответ, превратив его код в расширение, которое перегружает метод Replace
по умолчанию.
public static class StringExtensions
{
public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison)
{
StringBuilder sb = new StringBuilder();
int previousIndex = 0;
int index = str.IndexOf(oldValue, comparison);
while (index != -1)
{
sb.Append(str.Substring(previousIndex, index - previousIndex));
sb.Append(newValue);
index += oldValue.Length;
previousIndex = index;
index = str.IndexOf(oldValue, index, comparison);
}
sb.Append(str.Substring(previousIndex));
return sb.ToString();
}
}
Ответ 9
На основании ответа Джеффа Редди, с некоторыми оптимизациями и проверками:
public static string Replace(string str, string oldValue, string newValue, StringComparison comparison)
{
if (oldValue == null)
throw new ArgumentNullException("oldValue");
if (oldValue.Length == 0)
throw new ArgumentException("String cannot be of zero length.", "oldValue");
StringBuilder sb = null;
int startIndex = 0;
int foundIndex = str.IndexOf(oldValue, comparison);
while (foundIndex != -1)
{
if (sb == null)
sb = new StringBuilder(str.Length + (newValue != null ? Math.Max(0, 5 * (newValue.Length - oldValue.Length)) : 0));
sb.Append(str, startIndex, foundIndex - startIndex);
sb.Append(newValue);
startIndex = foundIndex + oldValue.Length;
foundIndex = str.IndexOf(oldValue, startIndex, comparison);
}
if (startIndex == 0)
return str;
sb.Append(str, startIndex, str.Length - startIndex);
return sb.ToString();
}
Ответ 10
версия, похожая на C. Dragon's, но если вам нужна только одна замена:
int n = myText.IndexOf(oldValue, System.StringComparison.InvariantCultureIgnoreCase);
if (n >= 0)
{
myText = myText.Substring(0, n)
+ newValue
+ myText.Substring(n + oldValue.Length);
}
Ответ 11
Вот еще один вариант для замены Regex, поскольку не многие люди, похоже, замечают, что совпадения содержат местоположение внутри строки:
public static string ReplaceCaseInsensative( this string s, string oldValue, string newValue ) {
var sb = new StringBuilder(s);
int offset = oldValue.Length - newValue.Length;
int matchNo = 0;
foreach (Match match in Regex.Matches(s, Regex.Escape(oldValue), RegexOptions.IgnoreCase))
{
sb.Remove(match.Index - (offset * matchNo), match.Length).Insert(match.Index - (offset * matchNo), newValue);
matchNo++;
}
return sb.ToString();
}
Ответ 12
Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase);
Ответ 13
Метод регулярного выражения должен работать. Однако то, что вы также можете сделать, - это нижний регистр строки из базы данных, в нижнем регистре% переменных% у вас есть, а затем найдите позиции и длины в нижней строковой строке из базы данных. Помните, что позиции в строке не меняются только потому, что ее нижняя обложка.
Затем, используя цикл, который идет в обратном порядке (проще, если вам это не нужно, вам нужно будет сохранить счетчик времени, куда будут перемещаться более поздние точки) удалите из своей строки с нижней строкой из базы данных% variables% by их положение и длину и вставить значения замены.