有没有替代string。replace是不区分大小写?

我需要search一个string,并用从数据库中提取的值replace所有出现的%FirstName%%PolicyAmount% 。 问题是名字的大小不一。 这阻止了我使用String.Replace()方法。 我已经看到有关这个主题的网页

 Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase); 

但是,由于某种原因,当我尝试用$0replace%PolicyAmount% ,replace永远不会发生。 我认为这与美元符号是正则expression式中的保留字符有关。

有没有另一种方法,我可以使用,不涉及消毒input处理正则expression式特殊字符?

来自MSDN
$ 0 – “replace组号码(十进制)匹配的最后一个子string。”

在.NET正则expression式组0始终是整个匹配。 对于文字$你需要

 string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase); 

看起来像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(); } 

这是一个扩展方法。 不知道我在哪里find它。

 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; } } 

似乎最简单的方法就是简单地使用.Net自带的Replace方法,自从.Net 1.0开始,

 string res = Microsoft.VisualBasic.Strings.Replace(res, "%PolicyAmount%", "$0", Compare: Microsoft.VisualBasic.CompareMethod.Text); 

为了使用这种方法,你必须添加一个引用到Microsoft.VisualBasic集合。 这个程序集是.Net运行时的标准部分,它不是一个额外的下载或标记为过时的。

这种混淆的答案组,部分原因在于问题的标题实际上比被问到的具体问题大得多。 读过之后,我不确定任何答案是从这里吸收所有好东西的一些编辑,所以我想我会试着总结一下。

这里有一个扩展方法,我认为这个方法避免了这里提到的陷阱,并提供了最广泛适用的解决scheme。

 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); } 

所以…

  • 这是@MarkRobinson 的扩展方法
  • 这不会试图跳过正则expression式 @Helge(如果你想在正则expression式之外进行string嗅探,你必须逐字节地执行)
  • 通过@MichaelLiu的优秀testing用例 "œ".ReplaceCaseInsensitiveFind("oe", "") ,虽然他可能有一个稍微不同的行为。

不幸的是, @HA评论说你必须Escape所有三个是不正确的 。 初始值和newValue不需要。

注意:但是, 如果它们是“捕获值”标记的一部分,则必须在要插入的新值中转义$ s。 这样Regex中的三个美元符号就代替了Regex.Replace [原文如此]。 没有这个,这样的事情打破了…

"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. 

告诉你什么,我知道对正则expression式感到舒适的人觉得他们的使用避免了错误,但我仍然偏向于字节嗅探string(但只有在阅读Spolsky编码之后 )才能确定你得到了你用于重要的用例。 让我想起克罗克福德一点“ 不安全的正则expression式 ”。 我们经常写正则expression式来允许我们想要的东西(如果我们是幸运的),但是无意中允许更多的东西(例如, $10真的是我的newValue正则expression式中有效的“捕获值”string?),因为我们没有体贴足够。 两种方法都有价值,并且都鼓励不同types的无意的错误。 低估复杂性往往是容易的。

这怪异的$逃避(和Regex.Escape没有逃脱捕获的价值模式,如$0如我所期望的替代值)使我疯狂了一段时间。 编程很难(c)1842年

  /// <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); } 

受到cfeduke的回答的启发,我做了使用IndexOf的函数来查找string中的旧值,然后用新值replace它。 我在一个处理数百万行的SSIS脚本中使用了这个,而正则expression式方法比这个慢得多。

 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's 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; } 

通过将他的代码变成一个扩展默认的Replace方法的扩展,扩展了C. Dragon 76的stream行答案。

 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(); } } 

根据Jeff Reddy的回答,经过一些优化和validation:

 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(); } 

一个类似于C. Dragon的版本,但是如果你只需要一个replace:

 int n = myText.IndexOf(oldValue, System.StringComparison.InvariantCultureIgnoreCase); if (n >= 0) { myText = myText.Substring(0, n) + newValue + myText.Substring(n + oldValue.Length); } 

这是执行Regexreplace的另一个选项,因为没有多less人似乎注意到匹配包含string中的位置:

  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(); } 
 Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase); 

正则expression式方法应该工作。 然而,你也可以做的是从数据库中小写string,小写你的%variables%,然后从数据库中find下面的string中的位置和长度。 请记住,string中的位置不会因为下方的位置而改变。

然后使用一个反向的循环(如果你不这样做,你将不得不保留一个运行的数据),从数据库中的非小写string中移除%variables%长度并插入replace值。