C# 是否有不区分大小写的 string.Replace 替代方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/244531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:37:31  来源:igfitidea点击:

Is there an alternative to string.Replace that is case-insensitive?

c#.netstring.net-2.0replace

提问by Aheho

I need to search a string and replace all occurrences of %FirstName%and %PolicyAmount%with a value pulled from a database. The problem is the capitalization of FirstName varies. That prevents me from using the String.Replace()method. I've seen web pages on the subject that suggest

我需要搜索一个字符串并用从数据库中提取的值替换所有出现的%FirstName%%PolicyAmount%。问题是 FirstName 的大小写不同。这使我无法使用该String.Replace()方法。我已经看到有关该主题的网页建议

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

However for some reason when I try and replace %PolicyAmount%with $0, the replacement never takes place. I assume that it has something to do with the dollar sign being a reserved character in regex.

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

Is there another method I can use that doesn't involve sanitizing the input to deal with regex special characters?

我可以使用另一种方法来处理输入以处理正则表达式特殊字符吗?

采纳答案by Todd White

From MSDN
$0 - "Substitutes the last substring matched by group number number (decimal)."

来自 MSDN
$0 -“替换与组号(十进制)匹配的最后一个子字符串。”

In .NET Regular expressions group 0 is always the entire match. For a literal $ you need to

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

string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$
Regex.Replace(strInput, strToken.Replace("$", "[$]"), strReplaceWith, RegexOptions.IgnoreCase);
", RegexOptions.IgnoreCase);

回答by Joel Coehoorn

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

回答by cfeduke

The regular expression method should work. However what you can also do is lower case the string from the database, lower case the %variables% you have, and then locate the positions and lengths in the lower cased string from the database. Remember, positions in a string don't change just because its lower cased.

正则表达式方法应该可以工作。但是,您还可以做的是将数据库中的字符串小写,将您拥有的 %variables% 小写,然后从数据库中找到小写字符串中的位置和长度。请记住,字符串中的位置不会仅仅因为它的小写而改变。

Then using a loop that goes in reverse (its easier, if you do not you will have to keep a running count of where later points move to) remove from your non-lower cased string from the database the %variables% by their position and length and insert the replacement values.

然后使用反向循环(它更容易,如果你不这样做,你将不得不保持运行计数后点移动到的位置)从数据库中的非小写字符串中删除 %variables% 按它们的位置和长度并插入替换值。

回答by C. Dragon 76

Seems like string.Replaceshouldhave an overload that takes a StringComparisonargument. Since it doesn't, you could try something like this:

似乎string.Replace应该有一个带StringComparison参数的重载。既然没有,你可以尝试这样的事情:

string res = Microsoft.VisualBasic.Strings.Replace(res, 
                                   "%PolicyAmount%", 
                                   "
int n = myText.IndexOf(oldValue, System.StringComparison.InvariantCultureIgnoreCase);
if (n >= 0)
{
    myText = myText.Substring(0, n)
        + newValue
        + myText.Substring(n + oldValue.Length);
}
", Compare: Microsoft.VisualBasic.CompareMethod.Text);

回答by CleverPatrick

Seems the easiest method is simply to use the Replace method that ships with .Net and has been around since .Net 1.0:

似乎最简单的方法是简单地使用 .Net 附带的 Replace 方法,并且自 .Net 1.0 以来一直存在:

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

}

In order to use this method, you have to add a Reference to the Microsoft.VisualBasic assemblly. This assembly is a standard part of the .Net runtime, it is not an extra download or marked as obsolete.

为了使用此方法,您必须添加对 Microsoft.VisualBasic 程序集的引用。此程序集是 .Net 运行时的标准部分,它不是额外的下载或标记为过时。

回答by Allanrbo

a version similar to C. Dragon's, but for if you only need a single replacement:

类似于 C. Dragon 的版本,但如果您只需要一个替换:

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

回答by rboarman

Here's an extension method. Not sure where I found it.

这是一个扩展方法。不知道我在哪里找到的。

public static string ReplaceCaseInsensitiveFind(this string str, string findMe,
    string newValue)
{
    return Regex.Replace(str,
        Regex.Escape(findMe),
        Regex.Replace(newValue, "\$[0-9]+", @"$$
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.
"), RegexOptions.IgnoreCase); }

回答by Karl Glennon

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

回答by ruffin

Kind of a confusing group of answers, in part because the title of the question is actually muchlarger than the specific question being asked. After reading through, I'm not sure any answer is a few edits away from assimilating all the good stuff here, so I figured I'd try to sum.

样的混乱组答案,部分原因是该问题的标题实际上是比的具体问题,更大的被问。通读完后,我不确定任何答案都需要进行一些编辑才能吸收这里的所有好东西,所以我想我会试着总结一下。

Here's an extension method that I think avoids the pitfalls mentioned here and provides the most broadly applicable solution.

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

##代码##

So...

所以...

  • This is an extension method@MarkRobinson
  • This doesn't try to skip Regex@Helge (you really have to do byte-by-byte if you want to string sniff like this outside of Regex)
  • Passes @MichaelLiu 's excellent test case, "?".ReplaceCaseInsensitiveFind("oe", ""), though he may have had a slightly different behavior in mind.

Unfortunately, @HA 's comment that you have to Escapeall three isn't correct. The initial value and newValuedoesn't need to be.

不幸的是,@HA 关于您必须对Escape所有三个的评论是不正确的。初始值,newValue不需要。

Note:You do, however, have to escape $s in the new value that you're inserting if they're part of what would appear to be a "captured value" marker. Thus the three dollar signs in the Regex.Replace inside the Regex.Replace [sic]. Without that, something like this breaks...

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

"This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")

"This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")

Here's the error:

这是错误:

##代码##

Tell you what, I know folks that are comfortable with Regex feel like their use avoids errors, but I'm often still partial to byte sniffing strings (but only after having read Spolsky on encodings) to be absolutely sure you're getting what you intended for important use cases. Reminds me of Crockford on "insecure regular expressions" a little. Too often we write regexps that allow what we want (if we're lucky), but unintentionally allow more in (eg, Is $10really a valid "capture value" string in my newValue regexp, above?) because we weren't thoughtful enough. Both methods have value, and both encourage different types of unintentional errors. It's often easy to underestimate complexity.

告诉你什么,我知道熟悉 Regex 的人觉得他们的使用可以避免错误,但我通常仍然偏爱字节嗅探字符串(但只有在阅读Spolsky on encodings 之后)才能绝对确定你得到了什么用于重要用例。让我想起了 Crockford 关于“不安全的正则表达式”的一点点。我们经常编写允许我们想要的东西的正则$10表达式(如果我们很幸运),但无意中允许更多的东西(例如,上面的 newValue regexp 中真的是一个有效的“捕获值”字符串吗?)因为我们不够周到. 这两种方法都有价值,并且都鼓励不同类型的无意错误。通常很容易低估复杂性。

That weird $escaping (and that Regex.Escapedidn't escape captured value patterns like $0as I would have expected in replacement values) drove me mad for a while. Programming Is Hard (c) 1842

这种奇怪的$转义(并且Regex.Escape没有像$0我在替换值中所期望的那样转义捕获的值模式)让我发疯了一段时间。编程很难 (c) 1842

回答by Brandon

Here is another option for executing Regex replacements, since not many people seem to notice the matches contain the location within the string:

这是执行正则表达式替换的另一个选项,因为似乎没有多少人注意到匹配项包含字符串中的位置:

##代码##