私のケースを作ってみましょう。よろしければ、私を千切りにすることができます。
Regexはこの問題の答えではありません-比較的言えば、遅すぎてメモリが不足しています。
StringBuilderは文字列マングリングよりもはるかに優れています。
これはを補足する拡張メソッドになるため、string.Replace
その動作を一致させることが重要だと思います。したがって、同じ引数の問題に対して例外をスローすることは、置換が行われなかった場合に元の文字列を返すことと同様に重要です。
StringComparisonパラメータを持つことは良い考えではないと思います。私はそれを試してみましたが、マイケル・リューによって最初に言及されたテストケースは問題を示しました:-
[TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]
IndexOfは一致しますが、ソース文字列の一致の長さ(1)とoldValue.Length(2)の間に不一致があります。これは、oldValue.Lengthが現在の一致位置に追加されたときに他のいくつかのソリューションでIndexOutOfRangeが発生し、これを回避する方法が見つからなかったことによって明らかになりました。とにかく正規表現はケースに一致しないので、私はStringComparison.OrdinalIgnoreCase
自分のソリューションにのみ使用するという実用的なソリューションを採用しました。
私のコードは他の回答と似ていますが、私の作成した問題は、を作成する前に一致を探すことStringBuilder
です。何も見つからない場合は、潜在的に大きな割り当てが回避されます。その後、コードdo{...}while
はwhile{...}
私は他のアンサーに対していくつかの広範なテストを行いましたが、これは部分的に速く出て、わずかに少ないメモリを使用しました。
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();
}