让我证明我的情况,然后如果你愿意,你可以把我撕成碎片。
正则表达式不是这个问题的答案 - 相对来说太慢而且内存太小。
StringBuilder 比字符串修饰要好得多。
由于这将是补充的扩展方法string.Replace
,因此我认为匹配其工作方式很重要 - 因此,对于相同的参数问题抛出异常很重要,如果没有进行替换,则返回原始字符串也是如此。
我相信拥有 StringComparison 参数不是一个好主意。我确实尝试过,但 michael-liu 最初提到的测试用例显示了一个问题:-
[TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]
虽然 IndexOf 将匹配,但源字符串 (1) 和 oldValue.Length (2) 中的匹配长度不匹配。当 oldValue.Length 添加到当前匹配位置时,这通过在其他一些解决方案中导致 IndexOutOfRange 表现出来,我找不到解决这个问题的方法。无论如何,正则表达式都无法匹配案例,所以我采取了仅StringComparison.OrdinalIgnoreCase
用于我的解决方案的务实解决方案。
我的代码与其他答案相似,但我的转折是我在麻烦创建StringBuilder
. 如果没有找到,则避免潜在的大分配。然后代码变成 ado{...}while
而不是 awhile{...}
我已经针对其他答案进行了一些广泛的测试,结果速度更快,并且使用的内存略少。
public static string ReplaceCaseInsensitive(this string str, string oldValue, string newValue)
{
if (str == null) throw new ArgumentNullException(nameof(str));
if (oldValue == null) throw new ArgumentNullException(nameof(oldValue));
if (oldValue.Length == 0) throw new ArgumentException("String cannot be of zero length.", nameof(oldValue));
var position = str.IndexOf(oldValue, 0, StringComparison.OrdinalIgnoreCase);
if (position == -1) return str;
var sb = new StringBuilder(str.Length);
var lastPosition = 0;
do
{
sb.Append(str, lastPosition, position - lastPosition);
sb.Append(newValue);
} while ((position = str.IndexOf(oldValue, lastPosition = position + oldValue.Length, StringComparison.OrdinalIgnoreCase)) != -1);
sb.Append(str, lastPosition, str.Length - lastPosition);
return sb.ToString();
}