Позвольте мне сделать мое дело, и тогда вы можете разорвать меня на куски, если хотите.
Regex не является решением этой проблемы - слишком медленно и, по большому счету, требует много памяти.
StringBuilder намного лучше, чем искажение строк.
Поскольку это будет метод расширения для дополнения string.Replace
, я считаю, что важно сопоставить, как это работает, поэтому важно создавать исключения для тех же проблем с аргументами, что и возврат исходной строки, если замена не была сделана. 1008 *
Я считаю, что наличие параметра StringComparison не очень хорошая идея.
Я попробовал, но тестовый пример, упомянутый Майклом-Лю, показал проблему: -
[TestCase("œ", "oe", "", StringComparison.InvariantCultureIgnoreCase, Result = "")]
Хотя IndexOf будет совпадать, существует несоответствие между длиной совпадения в исходной строке (1) и oldValue.Length (2). Это проявилось в появлении IndexOutOfRange в некоторых других решениях, когда oldValue.Length был добавлен к текущей позиции совпадения, и я не смог найти способ обойти это.
В любом случае, Regex не подходит к этому случаю, поэтому я выбрал прагматичное решение, используя только 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();
}