Lasciami fare il mio caso e poi puoi farmi a brandelli se vuoi.
Regex non è la risposta a questo problema: troppo lento e affamato di memoria, relativamente parlando.
StringBuilder è molto meglio della manipolazione delle stringhe.
Dal momento che questo sarà un metodo di estensione da integrare string.Replace
, ritengo sia importante abbinare il modo in cui funziona, pertanto è importante generare eccezioni per gli stessi argomenti, in quanto è necessario restituire la stringa originale se non è stata effettuata una sostituzione.
Credo che avere un parametro StringComparison non sia una buona idea. L'ho provato ma il test case originariamente menzionato da michael-liu ha mostrato un problema:
[TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]
Sebbene IndexOf corrisponderà, esiste una discrepanza tra la lunghezza della corrispondenza nella stringa di origine (1) e oldValue.Length (2). Ciò si è manifestato causando IndexOutOfRange in alcune altre soluzioni quando oldValue.Length è stato aggiunto alla posizione di corrispondenza corrente e non sono riuscito a trovare un modo per aggirare questo. Regex non riesce a eguagliare il caso, quindi ho preso la soluzione pragmatica di usare solo StringComparison.OrdinalIgnoreCase
per la mia soluzione.
Il mio codice è simile ad altre risposte, ma la mia svolta è che cerco una corrispondenza prima di andare nel guaio di creare un StringBuilder
. Se non viene trovato nessuno, viene evitata un'allocazione potenzialmente grande. Il codice diventa quindi un do{...}while
anziché unwhile{...}
Ho fatto alcuni test approfonditi contro altre Risposte e questo è risultato molto più veloce e ho usato un po 'meno memoria.
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();
}