C# 如何忽略String.replace中的大小写
如何将句子中的“camel”替换为“horse”,尽管有C# 如何忽略String.replace中的大小写,c#,string,replace,ignore-case,C#,String,Replace,Ignore Case,如何将句子中的“camel”替换为“horse”,尽管有字符串。replace不支持左字符串上的ignoreCase?使用正则表达式: string sentence = "We know it contains 'camel' word."; // Camel can be in different cases: string s1 = "CAMEL"; string s2 = "CaMEL"; string s3 = "CAMeL"; // ... string s4 = "Camel";
字符串。replace
不支持左字符串上的ignoreCase
?使用正则表达式:
string sentence = "We know it contains 'camel' word.";
// Camel can be in different cases:
string s1 = "CAMEL";
string s2 = "CaMEL";
string s3 = "CAMeL";
// ...
string s4 = "Camel";
// ...
string s5 = "camel";
当然,这也将匹配包含camel的单词,但不清楚您是否希望这样
如果需要精确匹配,可以使用自定义MatchEvaluator
var regex = new Regex( "camel", RegexOptions.IgnoreCase );
var newSentence = regex.Replace( sentence, "horse" );
与上一个示例一起使用,将匹配项包装为一个范围:
public static class Evaluators
{
public static string Wrap( Match m, string original, string format )
{
// doesn't match the entire string, otherwise it is a match
if (m.Length != original.Length)
{
// has a preceding letter or digit (i.e., not a real match).
if (m.Index != 0 && char.IsLetterOrDigit( original[m.Index - 1] ))
{
return m.Value;
}
// has a trailing letter or digit (i.e., not a real match).
if (m.Index + m.Length != original.Length && char.IsLetterOrDigit( original[m.Index + m.Length] ))
{
return m.Value;
}
}
// it is a match, apply the format
return string.Format( format, m.Value );
}
}
var regex=new regex(highlightedWord,RegexOptions.IgnoreCase);
foreach(句子中的var语句)
{
var evaluator=newmatchevaluator(match=>Evaluators.Wrap(匹配,句子,{0}));
Console.WriteLine(regex.Replace(句子,求值符));
}
您也可以使用String.IndexOf
这样做可能会比使用正则表达式获得更好的性能(我讨厌它们,因为它们不直观,也不容易出错,尽管这个简单的.Net函数调用抽象了实际混乱的正则表达式,并且没有提供太多的出错空间),但这可能不是您关心的问题;现在计算机真的很快,对吗?:)采用StringComparison对象的IndexOf重载允许您选择性地忽略大小写,并且由于IndexOf从指定位置返回第一个匹配项,您必须对循环进行编码,以处理多次出现的字符串。使用
StringComparison
,因为它非常方便OrdinalIgnoreCase
var regex = new Regex( highlightedWord, RegexOptions.IgnoreCase );
foreach (var sentence in sentences)
{
var evaluator = new MatchEvaluator( match => Evaluators.Wrap( match, sentence, "<span class='red'>{0}</span>" ) );
Console.WriteLine( regex.Replace( sentence, evaluator ) );
}
如果C#String类有一个类似Java的
ignoreCase()
方法,那当然好了。为String添加一个扩展方法来实现这一点:
用法:
string sentence = "We know it contains 'camel' word.";
string wordToFind = "camel";
string replacementWord = "horse";
int index = sentence.IndexOf(wordToFind , StringComparison.OrdinalIgnoreCase)
// Did we match the word regardless of case
bool match = index >= 0;
// perform the replace on the matched word
if(match) {
sentence = sentence.Remove(index, wordToFind.Length)
sentence = sentence.Insert(index, replacementWord)
}
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison,
bool recursive = true)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
if (!recursive)
{
return source;
}
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
代码:
它可能没有其他一些答案那么有效,但我有点喜欢sntbob编写的CustomReplace函数 然而,它有一个缺陷。如果文本替换是递归的,它将导致无限循环。例如,CustomReplace(“我吃香蕉!”,“an”,“banana”,false,false)将导致无限循环,字符串将继续变大。 例如,在第四次迭代之后,字符串将是“我吃BBBBB anaanaanaas!” 如果您只想在“香蕉”中替换“an”的两个实例,那么您必须采取另一种方法。我修改了sntbob的代码来解释这个案例。我承认它要复杂得多,但它可以处理递归替换
public static string CustomReplace(string srcText, string toFind, string toReplace, bool matchCase, bool replace0nce)
{
StringComparison sc = StringComparison.OrdinalIgnoreCase;
if (matchCase)
sc = StringComparison.Ordinal;
int pos;
while ((pos = srcText.IndexOf(toFind, sc)) > -1)
{
srcText = srcText.Remove(pos, toFind.Length);
srcText = srcText.Insert(pos, toReplace);
if (replace0nce)
break;
}
return srcText;
}
下面是一个使用string.IndexOf进行StringComparison的扩展方法:
public static string CustomReplace(string srcText, string toFind, string toReplace, bool matchCase, bool replaceOnce)
{
StringComparison sc = StringComparison.OrdinalIgnoreCase;
if (matchCase)
sc = StringComparison.Ordinal;
int pos;
int previousProcessedLength = 0;
string alreadyProcessedTxt = "";
string remainingToProcessTxt = srcText;
while ((pos = remainingToProcessTxt.IndexOf(toFind, sc)) > -1)
{
previousProcessedLength = alreadyProcessedTxt.Length;
//Append processed text up until the end of the found string and perform replacement
alreadyProcessedTxt += remainingToProcessTxt.Substring(0, pos + toFind.Length);
alreadyProcessedTxt = alreadyProcessedTxt.Remove(previousProcessedLength + pos, toFind.Length);
alreadyProcessedTxt = alreadyProcessedTxt.Insert(previousProcessedLength + pos, toReplace);
//Remove processed text from remaining
remainingToProcessTxt = remainingToProcessTxt.Substring(pos + toFind.Length);
if (replaceOnce)
break;
}
return alreadyProcessedTxt + remainingToProcessTxt;
}
顺便说一句,这里还有一个类似的Contains方法,也进行了StringComparison:
[Pure]
public static string Replace(this string source, string oldValue, string newValue, StringComparison comparisonType)
{
if (source.Length == 0 || oldValue.Length == 0)
return source;
var result = new System.Text.StringBuilder();
int startingPos = 0;
int nextMatch;
while ((nextMatch = source.IndexOf(oldValue, startingPos, comparisonType)) > -1)
{
result.Append(source, startingPos, nextMatch - startingPos);
result.Append(newValue);
startingPos = nextMatch + oldValue.Length;
}
result.Append(source, startingPos, source.Length - startingPos);
return result.ToString();
}
一些测试:
[Pure]
public static bool Contains(this string source, string value, StringComparison comparisonType)
{
return source.IndexOf(value, comparisonType) >= 0;
}
这是我的扩展方法,它结合了的递归性和对指出的错误的更清晰的修复 代码: 用法:
string sentence = "We know it contains 'camel' word.";
string wordToFind = "camel";
string replacementWord = "horse";
int index = sentence.IndexOf(wordToFind , StringComparison.OrdinalIgnoreCase)
// Did we match the word regardless of case
bool match = index >= 0;
// perform the replace on the matched word
if(match) {
sentence = sentence.Remove(index, wordToFind.Length)
sentence = sentence.Insert(index, replacementWord)
}
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison,
bool recursive = true)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
if (!recursive)
{
return source;
}
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
结果:
巴纳纳纳
如果您仍然希望递归性质是可选的:
代码:
用法:
string sentence = "We know it contains 'camel' word.";
string wordToFind = "camel";
string replacementWord = "horse";
int index = sentence.IndexOf(wordToFind , StringComparison.OrdinalIgnoreCase)
// Did we match the word regardless of case
bool match = index >= 0;
// perform the replace on the matched word
if(match) {
sentence = sentence.Remove(index, wordToFind.Length)
sentence = sentence.Insert(index, replacementWord)
}
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison,
bool recursive = true)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
if (!recursive)
{
return source;
}
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
结果:
巴纳纳纳
这里还有另一种选择,它使用StringComparison作为扩展方法。在StringBuilder对象上。我读过一些文章,指出StringBuilder使用内存可能比使用字符串更高效。如果需要的话,您可以很容易地修改它来处理字符串
string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase, false));
//
///查找/替换的扩展方法替换StringBuilder对象中的文本
///
///源StringBuilder对象
///要搜索的字符串
///字符串以替换每次发生的旧字符串
///要使用的字符串比较
///原始Stringbuilder及其替换件
公共静态StringBuilder替换(此StringBuilder原件,
字符串oldString、字符串newString、字符串比较StringComparison(字符串比较)
{
//如果有任何内容为空,或者oldString为空,请使用原始值退出
if(newString==null | | original==null | | string.IsNullOrEmpty(oldString))
归还原件;
//转换为字符串并使用
//IndexOf,它允许我们使用StringComparison。
int pos=original.ToString().IndexOf(oldString,0,stringComparison);
//循环直到找到并替换所有匹配项
而(位置>=0)
{
//移除旧字符串并插入新字符串。
原始。删除(pos,oldString.Length)。插入(pos,newString);
//在最后一次替换后,从1个字符开始获取下一个匹配(以避免可能的无限循环)
pos=original.ToString().IndexOf(oldString,pos+newString.Length+1,stringComparison);
}
归还原件;
}
为什么不导入Microsoft.VisualBasic命名空间并使用VB字符串.Replace方法
乙二醇
vbTextCompare强制进行不区分大小写的替换。工作完成了
好吧,它不是“纯”C#,但它能让你以更少的复杂性和混乱到达你想要去的地方。在库和框架时代,这需要大量的检查和调试性能往往是受害者。这就是堆栈溢出的原因。;)如果我只匹配那个词呢?我需要匹配文本中的一些关键字,并用关键字替换它们(并且仅替换它们),以便使它们变成红色。@Luca-我可能会使用一个自定义的MatchEvaluator来检查匹配的子字符串后面或前面是否有字母或数字,并且仅在不发生这种情况时才返回替换字符串。我将添加一个示例(可能是不完整的,并且经过了最低限度的测试)。@minitech好吧,如果单词边界真的有效,当然,但在他的示例中,他想替换引号中的一个单词。我认为本例中的单词边界是引号字符,而不是第一个“c”。自定义匹配计算器允许使用简化的正则表达式执行任意逻辑。啊。“向后看”可能也有用,但我知道这两种方法都是值得的!您还应该在正则表达式的模式上使用Regex.Escape()。这只会替换
源代码中第一次出现的oldString
,与此不同