字符串。替换忽略大小写

我有一个名为hello world的字符串

我需要把"world"换成" chsharp "

我用:

string.Replace("World", "csharp");

但结果是,字符串没有被替换。原因在于区分大小写。原来的字符串包含“世界”,而我试图取代“世界”。

有没有办法避免字符串中的这种区分大小写的情况?替代方法?

195769 次浏览

你可以使用正则表达式并执行不区分大小写的替换:

class Program
{
static void Main()
{
string input = "hello WoRlD";
string result =
Regex.Replace(input, "world", "csharp", RegexOptions.IgnoreCase);
Console.WriteLine(result); // prints "hello csharp"
}
}

(编辑:没有意识到“裸链接”问题,对不起)

摘自在这里:

string myString = "find Me and replace ME";
string strReplace = "me";
myString = Regex.Replace(myString, "me", strReplace, RegexOptions.IgnoreCase);

似乎你不是第一个抱怨字符串不区分大小写的人。

var search = "world";
var replacement = "csharp";
string result = Regex.Replace(
stringToLookInto,
Regex.Escape(search),
replacement.Replace("$","$$"),
RegexOptions.IgnoreCase
);

如果你依赖于包含正则表达式语言元素的用户输入,正则表达式。逃避是有用的

更新

多亏了注释,您实际上不必转义替换字符串。

这里有一个测试代码的小小提琴:

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

很多使用Regex的建议。如果没有它,这个扩展方法如何:

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, comparison)) != -1)
{
str = str.Remove(foundAt, old.Length).Insert(foundAt, @new);
foundAt += @new.Length;
}
return str;
}

修改了@Darky711的答案,使用传入的比较类型和匹配框架替换命名和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;
}

在搜索字符串上使用Regex.Escape扩展Petrucio的答案,并根据史蒂夫·B的答案中建议的转义匹配的组(以及一些小的更改):

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

你可以使用微软。VisualBasic命名空间来查找这个帮助函数:

Replace(sourceString, "replacethis", "withthis", , , CompareMethod.Text)

下面的函数是从字符串集中删除所有匹配的单词(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);
}

我写了扩展方法:

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

快2.5倍最有效的方法优于其他正则表达式方法:

/// <summary>
/// Returns a new string in which all occurrences of a specified string in the current instance are replaced with another
/// specified string according 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 occurrences of <paramref name="oldValue"/>.
/// If value is equal to <c>null</c>, than all occurrences of <paramref name="oldValue"/> will be removed from the <paramref name="str"/>.</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 <paramref name="oldValue"/> are replaced with <paramref name="newValue"/>.
/// If <paramref name="oldValue"/> is not found in the current instance, the method returns the current instance unchanged.</returns>
[DebuggerStepThrough]
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 behavior.
throw new ArgumentNullException(nameof(str));
}
if (str.Length == 0)
{
// Same as original .NET C# string.Replace behavior.
return str;
}
if (oldValue == null)
{
// Same as original .NET C# string.Replace behavior.
throw new ArgumentNullException(nameof(oldValue));
}
if (oldValue.Length == 0)
{
// Same as original .NET C# string.Replace behavior.
throw new ArgumentException("String cannot be of zero length.");
}




//if (oldValue.Equals(newValue, comparisonType))
//{
//This condition has no sense
//It will prevent method from replacesing: "Example", "ExAmPlE", "EXAMPLE" to "example"
//return str;
//}






// Prepare string builder for storing the processed string.
// Note: StringBuilder has a better performance than String by 30-40%.
StringBuilder resultStringBuilder = new StringBuilder(str.Length);






// Analyze the replacement: replace or remove.
bool isReplacementNullOrEmpty = string.IsNullOrEmpty(@newValue);






// Replace all values.
const int valueNotFound = -1;
int foundAt;
int startSearchFromIndex = 0;
while ((foundAt = str.IndexOf(oldValue, startSearchFromIndex, comparisonType)) != valueNotFound)
{


// Append all characters until the found replacement.
int @charsUntilReplacment = foundAt - startSearchFromIndex;
bool isNothingToAppend = @charsUntilReplacment == 0;
if (!isNothingToAppend)
{
resultStringBuilder.Append(str, startSearchFromIndex, @charsUntilReplacment);
}






// Process the replacement.
if (!isReplacementNullOrEmpty)
{
resultStringBuilder.Append(@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. For example: 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 + oldValue.Length;
if (startSearchFromIndex == str.Length)
{
// It is end of the input string: no more space for the next search.
// The input string ends with a value that has already been replaced.
// Therefore, the string builder with the result is complete and no further action is required.
return resultStringBuilder.ToString();
}
}




// Append the last part to the result.
int @charsUntilStringEnd = str.Length - startSearchFromIndex;
resultStringBuilder.Append(str, startSearchFromIndex, @charsUntilStringEnd);




return resultStringBuilder.ToString();


}

注意:忽略大小写 == StringComparison.OrdinalIgnoreCase作为StringComparison comparisonType的参数。它是替换所有值的最快、不区分大小写的方法。


该方法的优点:

  • 高CPU和内存效率;
  • 这是最快的解决方案,比其他方法快2.5倍 使用正则表达式(最后证明);
  • 适用于从输入字符串中删除部分(将newValue设置为 null),为此优化;
  • 与原来的net c# string.Replace行为相同,相同的异常;
  • 评论得好,容易理解;
  • 更简单——没有正则表达式。正则表达式总是比较慢,因为它们的多功能性(即使是编译过的);
  • 这种方法经过了很好的测试,在其他人的解决方案中没有像无限循环这样的隐藏缺陷,甚至评分很高:

@AsValeO: Not适用于Regex语言元素,所以它不是 通用方法< / p > @Mike Stillion:这段代码有问题。如果文本为new 是旧文本的超集,这会产生一个无限循环。


Benchmark-proof:这个解决方案比@Steve B.的regex快2.59倍倍,代码:

// Results:
// 1/2. Regular expression solution: 4486 milliseconds
// 2/2. Current solution: 1727 milliseconds — 2.59X times FASTER! than regex!


// Notes: the test was started 5 times, the result is an average; release build.


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

原创创意- @Darky711;感谢@ miner的StringBuilder

这样不行吗?我想象不出还有什么比这更快更简单的方法了。

public static class ExtensionMethodsString
{
public static string Replace(this String thisString, string oldValue, string newValue, StringComparison stringComparison)
{
string working = thisString;
int index = working.IndexOf(oldValue, stringComparison);
while (index != -1)
{
working = working.Remove(index, oldValue.Length);
working = working.Insert(index, newValue);
index = index + newValue.Length;
index = working.IndexOf(oldValue, index, stringComparison);
}
return working;
}
}

使用@Georgy Batalov解决方案时,我在使用以下示例时遇到了一个问题

string original = "blah,DC=bleh,DC=blih,DC=bloh,DC=com"; 字符串替换=原始。ReplaceIgnoreCase(“特区 =", ".")

下面是我如何重写他的扩展

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);
bool initialRun = true;


while (index >= 0)
{
string substr = result.Substring(0, index);
substr = substr + newVale;
result = result.Remove(0, index);
result = result.Remove(0, oldVale.Length);


stringBuilder.Append(substr);


index = result.IndexOf(oldVale, StringComparison.InvariantCultureIgnoreCase);
}


if (result.Length > 0)
{
stringBuilder.Append(result);
}


return stringBuilder.ToString();
}

我更喜欢这个- "Hello World". tolower()。Replace("world", " chsharp ");

你也可以尝试Regex类。

var regex = new regex ("camel", RegexOptions。IgnoreCase); var newSentence =正则表达式。替换(句子,"horse");

.
< p >。Net Core内置了这个方法: Replace(String, String, StringComparison) 医生。现在我们可以简单地写: "...".Replace("oldValue", "newValue", StringComparison.OrdinalIgnoreCase) < / p >

使用这个,测试和100%工作!

VB。网

Dim myString As String
Dim oldValue As String
Dim newValue As String


myString = Form1.TextBox1.Text
oldValue = TextBox1.Text
newValue = TextBox2.Text


Dim working As String = myString
Dim index As Integer = working.IndexOf(oldValue, StringComparison.CurrentCultureIgnoreCase)


While index <> -1
working = working.Remove(index, oldValue.Length)
working = working.Insert(index, newValue)
index = index + newValue.Length
index = working.IndexOf(oldValue, index, StringComparison.CurrentCultureIgnoreCase)
Form1.TextBox1.Text = working
End While

为c#

private void Button2_Click(System.Object sender, System.EventArgs e)
{
string myString;
string oldValue;
string newValue;


myString = Form1.TextBox1.Text;
oldValue = TextBox1.Text;
newValue = TextBox2.Text;


string working = myString;
int index = working.IndexOf(oldValue, StringComparison.CurrentCultureIgnoreCase);


while (index != -1)
{
working = working.Remove(index, oldValue.Length);
working = working.Insert(index, newValue);
index = index + newValue.Length;
index = working.IndexOf(oldValue, index, StringComparison.CurrentCultureIgnoreCase);
Form1.TextBox1.Text = working;
}
}

我的这个方法可以忽略大小写以及只选择整个单词

public static string Replace(this string s, string word, string by, StringComparison stringComparison, bool WholeWord)
{
s = s + " ";
int wordSt;
StringBuilder sb = new StringBuilder();
while (s.IndexOf(word, stringComparison) > -1)
{
wordSt = s.IndexOf(word, stringComparison);
if (!WholeWord || ((wordSt == 0 || !Char.IsLetterOrDigit(char.Parse(s.Substring(wordSt - 1, 1)))) && !Char.IsLetterOrDigit(char.Parse(s.Substring(wordSt + word.Length, 1)))))
{
sb.Append(s.Substring(0, wordSt) + by);
}
else
{
sb.Append(s.Substring(0, wordSt + word.Length));
}
s = s.Substring(wordSt + word.Length);
}
sb.Append(s);
return sb.ToString().Substring(0, sb.Length - 1);
}

另一种方法是使用选项接受StringComparison。CurrentCultureIgnoreCase忽略String.Replace()中的大小写敏感性

string.Replace("World", "csharp", StringComparison.CurrentCultureIgnoreCase)

我推荐StringComparison。CurrentCultureIgnoreCase方法由ZZY / Gama Sharma提出。这是另一个可以用于LINQ的技术:

List<string> ItemsToRedact = new List<string> { "star", "citizen", "test", "universe"};


string Message = "Just like each sTaR is unique yet mAkes the uniVERSE what it is, the light in you makes you who you are";


List<string> ReplacementList = Message.Split(' ').Where(x => ItemsToRedact.Contains(x.ToLower())).ToList();


foreach (var word in ReplacementList)
{
Message = Message.Replace(word, "[Redacted] ");
}


Console.WriteLine(Message);

就像每个人都是独一无二的一样,你身上的光芒也造就了你

这段代码可以进一步提炼,但为了可读性,我将其分解了