Lassen Sie mich meinen Fall machen und dann können Sie mich in Stücke reißen, wenn Sie möchten.
Regex ist nicht die Antwort auf dieses Problem - relativ gesehen zu langsam und speicherhungrig.
StringBuilder ist viel besser als String Mangling.
Da dies eine ergänzende Erweiterungsmethode sein wird, halte string.Replace
ich es für wichtig, die Funktionsweise anzupassen. Daher ist es wichtig, Ausnahmen für dieselben Argumentprobleme auszulösen, wie die Rückgabe der ursprünglichen Zeichenfolge, wenn keine Ersetzung vorgenommen wurde.
Ich glaube, dass ein StringComparison-Parameter keine gute Idee ist. Ich habe es versucht, aber der ursprünglich von Michael-Liu erwähnte Testfall zeigte ein Problem:
[TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]
Während IndexOf übereinstimmt, besteht eine Nichtübereinstimmung zwischen der Länge der Übereinstimmung in der Quellzeichenfolge (1) und oldValue.Length (2). Dies manifestierte sich darin, dass IndexOutOfRange in einigen anderen Lösungen verursacht wurde, als oldValue.Length zur aktuellen Übereinstimmungsposition hinzugefügt wurde und ich keinen Weg fand, dies zu umgehen. Da Regex ohnehin nicht mit dem Fall übereinstimmt, habe ich die pragmatische Lösung gewählt, nur StringComparison.OrdinalIgnoreCase
für meine Lösung zu verwenden.
Mein Code ähnelt anderen Antworten, aber meine Wendung ist, dass ich nach einer Übereinstimmung suche, bevor ich mir die Mühe mache, eine zu erstellen StringBuilder
. Wenn keine gefunden wird, wird eine möglicherweise große Zuordnung vermieden. Der Code wird dann do{...}while
eher zu einem als zu einemwhile{...}
Ich habe einige umfangreiche Tests mit anderen Antworten durchgeführt und diese kamen etwas schneller heraus und verbrauchten etwas weniger Speicher.
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();
}