String.Replace忽略大小写
我有一个名为“hello world”的string
我需要把“世界”这个词replace成“csharp”
为此我使用:
string.Replace("World", "csharp");
但结果是,我没有取代string。 原因是区分大小写。 原始的string包含“世界”,而我试图取代“世界”。
有没有办法避免这种情况下string.Replace方法的敏感性?
您可以使用正则expression式并执行不区分大小写的replace:
class Program { static void Main() { string input = "hello WoRlD"; string result = Regex.Replace(input, "world", "csharp", RegexOptions.IgnoreCase); Console.WriteLine(result); // prints "hello csharp" } }
var search = "world"; var replacement = "csharp"; string result = Regex.Replace( stringToLookInto, Regex.Escape(search), replacement.Replace("$","$$"), RegexOptions.IgnoreCase );
如果您依赖于可以包含Regex语言元素的用户input,则Regex.Escape非常有用
更新
感谢评论,你实际上不必逃避replacestring。
这是一个testing代码的小提琴 :
using System; using System.Text.RegularExpressions; public class Program { public static void Main() { var tests = new[] { new { Input="abcdef", Search="abc", Replacement="xyz", Expected="xyzdef" }, new { Input="ABCdef", Search="abc", Replacement="xyz", Expected="xyzdef" }, new { Input="A*BCdef", Search="a*bc", Replacement="xyz", Expected="xyzdef" }, new { Input="abcdef", Search="abc", Replacement="x*yz", Expected="x*yzdef" }, new { Input="abcdef", Search="abc", Replacement="$", Expected="$def" }, }; foreach(var test in tests){ var result = ReplaceCaseInsensitive(test.Input, test.Search, test.Replacement); Console.WriteLine( "Success: {0}, Actual: {1}, {2}", result == test.Expected, result, test ); } } private static string ReplaceCaseInsensitive(string input, string search, string replacement){ string result = Regex.Replace( input, Regex.Escape(search), replacement.Replace("$","$$"), RegexOptions.IgnoreCase ); return result; } }
它的输出是:
Success: True, Actual: xyzdef, { Input = abcdef, Search = abc, Replacement = xyz, Expected = xyzdef } Success: True, Actual: xyzdef, { Input = ABCdef, Search = abc, Replacement = xyz, Expected = xyzdef } Success: True, Actual: xyzdef, { Input = A*BCdef, Search = a*bc, Replacement = xyz, Expected = xyzdef } Success: True, Actual: x*yzdef, { Input = abcdef, Search = abc, Replacement = x*yz, Expected = x*yzdef} Success: True, Actual: $def, { Input = abcdef, Search = abc, Replacement = $, Expected = $def }
扩展使我们的生活更轻松:
static public class StringExtensions { static public string ReplaceInsensitive(this string str, string from, string to) { str = Regex.Replace(str, from, to, RegexOptions.IgnoreCase); return str; } }
很多使用正则expression式的build议。 没有它的扩展方法如何:
public static string Replace(this string str, string old, string @new, StringComparison comparison) { @new = @new ?? ""; if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(old) || old.Equals(@new, comparison)) return str; int foundAt = 0; while ((foundAt = str.IndexOf(old, foundAt, StringComparison.CurrentCultureIgnoreCase)) != -1) { str = str.Remove(foundAt, old.Length).Insert(foundAt, @new); fountAt += @new.Length; } return str; }
( 编辑:没有意识到“裸链”的问题,对此感到遗憾)
采取从这里 :
string myString = "find Me and replace ME"; string strReplace = "me"; myString = Regex.Replace(myString, "me", strReplace, RegexOptions.IgnoreCase);
似乎你不是第一个抱怨缺less不区分大小写的string。replace。
您可以使用Microsoft.Visualbasic命名空间来查找此辅助函数:
Replace(sourceString, "replacethis", "withthis", , , CompareMethod.Text)
修改@Denny711的答案是使用传入的比较types,并尽可能匹配框架来replace命名和xml注释。
/// <summary> /// Returns a new string in which all occurrences of a specified string in the current instance are replaced with another specified string. /// </summary> /// <param name="str">The string performing the replace method.</param> /// <param name="oldValue">The string to be replaced.</param> /// <param name="newValue">The string replace all occurrances of oldValue.</param> /// <param name="comparisonType">Type of the comparison.</param> /// <returns></returns> public static string Replace(this string str, string oldValue, string @newValue, StringComparison comparisonType) { @newValue = @newValue ?? string.Empty; if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(oldValue) || oldValue.Equals(@newValue, comparisonType)) { return str; } int foundAt; while ((foundAt = str.IndexOf(oldValue, 0, comparisonType)) != -1) { str = str.Remove(foundAt, oldValue.Length).Insert(foundAt, @newValue); } return str; }
我写了扩展方法:
public static string ReplaceIgnoreCase(this string source, string oldVale, string newVale) { if (source.IsNullOrEmpty() || oldVale.IsNullOrEmpty()) return source; var stringBuilder = new StringBuilder(); string result = source; int index = result.IndexOf(oldVale, StringComparison.InvariantCultureIgnoreCase); while (index >= 0) { if (index > 0) stringBuilder.Append(result.Substring(0, index)); if (newVale.IsNullOrEmpty().IsNot()) stringBuilder.Append(newVale); stringBuilder.Append(result.Substring(index + oldVale.Length)); result = stringBuilder.ToString(); index = result.IndexOf(oldVale, StringComparison.InvariantCultureIgnoreCase); } return result; }
对于以前的扩展方法,我使用了另外两个扩展方法
public static bool IsNullOrEmpty(this string value) { return string.IsNullOrEmpty(value); } public static bool IsNot(this bool val) { return val == false; }
FINAL扩展方法(基于@Dety711解决scheme)没有正则expression式 :
正则expression式的缺点:
我:正则expression式总是比较慢(在这个味精的结尾有证据 )。 我们为什么要用正则expression式,如果我们可以更容易地进行replace呢?
最强的@Darin Dimitrov解决scheme> @AsValeO:不适用于正则expression式语言元素,所以它不是通用的方法
并没有无限循环 :
@Mike Stillion:这个代码有问题。 如果new中的文本是旧文本的超集,则会产生无限循环。
也与评论和原始.NET C# string.Replace方法相同的行为 。
/// <summary> /// Returns a new string in which all occurrences of a specified string in the current instance are replaced with another /// specified string acording the type of search to use for the specified string. /// </summary> /// <param name="str">The string performing the replace method.</param> /// <param name="oldValue">The string to be replaced.</param> /// <param name="newValue">The string replace all occurrances of oldValue.</param> /// <param name="comparisonType">One of the enumeration values that specifies the rules for the search. </param> /// <returns>A string that is equivalent to the current string except that all instances of oldValue are replaced with newValue. /// If oldValue is not found in the current instance, the method returns the current instance unchanged. </returns> [DebuggerStepThrough()]//to prevent method from step-into (F11) public static string Replace(this string str, string oldValue, string @newValue, StringComparison comparisonType) { //Check inputs if (str == null) { //Same as original .NET C# string.Replace behaviour throw new ArgumentNullException(nameof(str)); } if (str.Length == 0) { //Same as original .NET C# string.Replace behaviour return str; } if (oldValue == null) { //Same as original .NET C# string.Replace behaviour throw new ArgumentNullException(nameof(oldValue)); } if (oldValue.Length == 0) { //Same as original .NET C# string.Replace behaviour throw new ArgumentException("String cannot be of zero length."); } //if (oldValue.Equals(newValue, comparisonType)) //{ //This condition has no sence //It will prevent method from replacesing: "Example", "ExAmPlE", "EXAMPLE" to "example" //return str; //} //Prepare replacment @newValue = @newValue ?? string.Empty; //Replace all values const int valueNotFound = -1; int foundAt, startSearchFromIndex = 0; while ((foundAt = str.IndexOf(oldValue, startSearchFromIndex, comparisonType)) != valueNotFound) { //Remove old value and insert new at the same place str = str.Remove(foundAt, oldValue.Length) .Insert(foundAt, @newValue); //Prepare start index for the next search //This needed to prevent infinite loop, otherwise method always start search //from the start of the string. So, if an oldValue == "EXAMPLE", newValue == "example" //and comparisonType == "any ignore case" will conquer to replacing: //"EXAMPLE" to "example" to "example" to "example" … infinite loop startSearchFromIndex = foundAt + @newValue.Length; if (startSearchFromIndex == str.Length) { //End of the input string: no more space for the next search break; } } return str; }
注1 :使用“StringComparison.OrdinalIgnoreCase”作为StringComparison comparisonType的参数。 这是最快,不区分大小写的方式来取代所有的值。
注2 ,基准certificate:这个解决scheme比正则expression式快了59%@Steve B.基准代码:
const int benchmarkIterations = 1000000; const string sourceString = "aaaaddsdsdsdsdsd"; const string oldValue = "D"; const string newValue = "Fod"; long totalLenght = 0; Stopwatch regexStopwatch = Stopwatch.StartNew(); string tempString1; for (int i = 0; i < benchmarkIterations; i++) { tempString1 = sourceString; tempString1 = ReplaceCaseInsensitive(tempString1, oldValue, newValue); totalLenght = totalLenght + tempString1.Length; } regexStopwatch.Stop(); Stopwatch currentSolutionStopwatch = Stopwatch.StartNew(); string tempString2; for (int i = 0; i < benchmarkIterations; i++) { tempString2 = sourceString; tempString2 = tempString2.Replace(oldValue, newValue, StringComparison.OrdinalIgnoreCase); totalLenght = totalLenght + tempString2.Length; } currentSolutionStopwatch.Stop(); //Results: //1/2. Regular expression solution: 4486 milliseconds //2/2. Current solution: 2819 milliseconds — +59% faster than regex
在searchstring中用正则Regex.Escape
扩展了Petrucio的回答,并按照Steve B的回答(以及对我的口味的一些小的改变)build议逃避匹配的组合:
public static class StringExtensions { public static string ReplaceIgnoreCase(this string str, string from, string to) { return Regex.Replace(str, Regex.Escape(from), to.Replace("$", "$$"), RegexOptions.IgnoreCase); } }
这将产生以下预期的结果:
Console.WriteLine("(heLLo) wOrld".ReplaceIgnoreCase("(hello) world", "Hi $1 Universe")); // Hi $1 Universe Console.WriteLine("heLLo wOrld".ReplaceIgnoreCase("(hello) world", "Hi $1 Universe")); // heLLo wOrld
但是,如果不执行转义,您将得到以下结果,这不是来自String.Replace
的预期行为,它只是区分大小写:
Console.WriteLine("(heLLo) wOrld".ReplaceIgnoreCase_NoEscaping("(hello) world", "Hi $1 Universe")); // (heLLo) wOrld Console.WriteLine("heLLo wOrld".ReplaceIgnoreCase_NoEscaping("(hello) world", "Hi $1 Universe")); // Hi heLLo Universe
下面的函数是从string集合中删除所有的匹配词(this)。 由Ravikant Sonare。
private static void myfun() { string mystring = "thiTHISThiss This THIS THis tThishiThiss. Box"; var regex = new Regex("this", RegexOptions.IgnoreCase); mystring = regex.Replace(mystring, ""); string[] str = mystring.Split(' '); for (int i = 0; i < str.Length; i++) { if (regex.IsMatch(str[i].ToString())) { mystring = mystring.Replace(str[i].ToString(), string.Empty); } } Console.WriteLine(mystring); }