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

Ahe*_*eho 301 .net c# string replace .net-2.0

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

Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);
Run Code Online (Sandbox Code Playgroud)

但是出于某些原因,当我尝试更换%PolicyAmount%$0,更换永远不会发生.我认为它与美元符号是正则表达式中的保留字符有关.

是否有其他方法可以使用,不涉及清理输入以处理正则表达式特殊字符?

C. *_* 76 294

似乎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();
}
Run Code Online (Sandbox Code Playgroud)

  • 同意上述评论.这可以使用相同的方法名称作为扩展方法.只需使用方法签名在静态类中弹出它:public static string Replace(this String str,string oldValue,string newValue,StringComparison comparison) (41认同)
  • 这是错误的; `ReplaceString("œ","oe","",StringComparison.InvariantCulture)`抛出`ArgumentOutOfRangeException`. (10认同)
  • 尼斯.我会将`ReplaceString`更改为`Replace`. (9认同)
  • 在单元测试的时候,我遇到了`oldValue == newValue ==""`时永远不会返回的情况. (9认同)
  • @Helge,一般来说,这可能没什么问题,但我必须从用户那里获取任意字符串,并且不会冒险输入对正则表达式有意义.当然,我想我可以写一个循环,并在每个角色前放一个反斜杠......那时,我不妨做上面的(恕我直言). (8认同)
  • 此外,这将比正则表达式更快. (3认同)
  • 速度不是万能的.使用正则表达式而不是自己动手,引入额外的复杂性,也可能还有bug.此外,正则表达式解决方案更易于阅读和维护. (2认同)
  • @Jim - 我同意使用这个解决方案,但万一你需要它,你可以使用[Regex.Escape](http://msdn.microsoft.com/en-us/library/system.text.regularexpressions .regex.escape.aspx)为你逃避正则表达式重要的角色. (2认同)
  • 对于oldValue =""的情况,String.Replace不允许它.我添加了异常检查以匹配String.Replace异常:`if(oldValue == null){throw new ArgumentNullException("oldValue"); } if(oldValue ==""){throw new ArgumentException("String不能为零长度.","oldValue"); }` (2认同)
  • 这里工作很棒.我把它变成了一个扩展方法,但更重要的是,在str不包含oldValue的情况下,我在顶部添加了一个fast-out.只需将`int index = str.IndexOf(oldValue,comparison);`移动到方法的第一行,如果`index == -1`则返回`str` (2认同)
  • 只需学习正则表达式,保持代码清洁.这是一个微不足道的例子,但看起来仍然很复杂.人们痴迷于速度,然后写这样糟糕的代码是不幸的. (2认同)
  • @Jaycee,默认情况下必须转义替换字符串对我来说看起来不像是干净的代码.此外,我确信实际的Regex实现本身看起来更复杂,并且可能在其初始版本中存在大量错误.我希望发布最终的无bug版本. (2认同)
  • 以这种方式使用`StringBuilder`可能不会以你想要的方式提高性能; 它将使用16个字符的缓冲区进行初始化,并且您的循环可能会导致大量内存分配和副本.在开始向其附加字符串之前,应将`StringBuilder`初始化为合适的容量. (2认同)

Tod*_*ite 130

从MSDN
$ 0 - "替换与组号(十进制)匹配的最后一个子字符串."

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

string value = Regex.Replace("%PolicyAmount%", "%PolicyAmount%", @"$$0", RegexOptions.IgnoreCase);
Run Code Online (Sandbox Code Playgroud)

  • 你应该转义这样的特殊字符:string value = Regex.Replace("%PolicyAmount%",Regex.Escape("%PolicyAmount%"),Regex.Escape("$ 0"),RegexOptions.IgnoreCase); (23认同)
  • 在这种特殊情况下这很好,但是在从外部输入字符串的情况下,人们不能确定它们不包含表示正则表达式中特殊内容的字符 (16认同)
  • 在Regex.Replace中使用Regex.Escape时请注意.你将不得不逃避传递的所有三个字符串,并在结果上调用Regex.Unescape! (8认同)
  • 根据msdn:"字符转义在正则表达式模式中被识别,但在替换模式中不被识别." (https://msdn.microsoft.com/en-us/library/4edbef7e.aspx) (4认同)

ruf*_*fin 43

混乱组答案,部分原因是由于问题的标题实际上是一种大于被问的具体问题.阅读完之后,我不确定任何答案是否能够吸收所有好东西的一些编辑,所以我想我会尝试总结.

这是一种扩展方法,我认为可以避免这里提到的陷阱,并提供最广泛适用的解决方案.

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);
}
Run Code Online (Sandbox Code Playgroud)

所以...

不幸的是,@ HA对你Escape所有三个人的评论是不正确的.初始值newValue并不需要.

注意:但是,如果它们是看似"捕获值"标记的一部分,则$必须在插入的新值中转义s .因此Regex.Replace里面的三个美元符号.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.
Run Code Online (Sandbox Code Playgroud)

告诉你吧,我知道,是舒适的正则表达式的人觉得自己的使用可以避免的错误,但我仍然经常偏字节(只读过之后,但闻弦斯波斯基上的编码),以绝对确保你得到你用于重要用例.让我想起克罗克福德对" 不安全的正则表达 "的看法.我们常常写正则表达式,让我们想要的(如果我们幸运的话),但无意让更多的(例如,是$10真正有效的"捕捉值"串在我的正则表达式NEWVALUE上面?),因为我们还不够周到.这两种方法都有价值,并且都鼓励不同类型的无意识错误.通常很容易低估复杂性.

奇怪的$逃避(Regex.Escape并没有逃脱被捕获的价值模式,就像$0我在替换价值中所期望的那样)让我疯了一会儿.编程很难(c)1842

  • 真的值得更多的选票.加1842年,哈哈.:) (3认同)

Cle*_*man 30

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

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

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

  • 有用.您需要添加对Microsoft.VisualBasic程序集的引用. (4认同)
  • Brain2000,你错了..NET中的所有字符串都是不可变的. (3认同)

rbo*_*man 30

这是一种扩展方法.不确定我在哪里找到它.

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

}
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案中存在多个错误:1.检查originalString,oldValue和newValue是否为null.2.不要返回orginalString(不起作用,简单类型不通过引用传递),但首先将orginalValue的值赋给新字符串并修改它并将其返回. (2认同)

Kar*_*non 10

    /// <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);
    }
Run Code Online (Sandbox Code Playgroud)


小智 8

受cfeduke的回答启发,我创建了这个函数,它使用IndexOf在字符串中查找旧值,然后用新值替换它.我在处理数百万行的SSIS脚本中使用了这个,而regex方法比这慢.

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;
}
Run Code Online (Sandbox Code Playgroud)


Cha*_*ehn 6

扩展C. Dragon 76的流行答案,将他的代码变成一个超载默认Replace方法的扩展.

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();
     }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*air 6

从 .NET Core 2.0 或 .NET Standard 2.1 开始,这已被纳入 .NET 运行时 [1]:

"hello world".Replace("World", "csharp", StringComparison.CurrentCultureIgnoreCase); // "hello csharp"
Run Code Online (Sandbox Code Playgroud)

[1] https://learn.microsoft.com/en-us/dotnet/api/system.string.replace#System_String_Replace_System_String_System_String_System_StringComparison _