Ах, радости от текста.
То, что вы, скорее всего, имеете там, но потерялись при публикации на SO, - это "мягкий дефис".
Чтобы воспроизвести проблему, я попробовал этот код в LINQPad :
void Main()
{
var text = "Test1 \u00ad Test2";
int index = text.IndexOf(" ");
while (index > 0)
{
text = text.Replace(" ", " ");
index = text.IndexOf(" ");
}
}
И, конечно же, приведенный выше код просто застревает в цикле.
Обратите внимание, что \u00ad
- это символ Unicode для Soft Hyphen, согласно CharMap. Вы также всегда можете скопировать и вставить символ из CharMap, но размещение его здесь на SO заменит его гораздо более распространенным кузеном, символом дефиса-минуса, Unicode u002d
(тот, что на вашей клавиатуре).
Вы можете прочитать небольшой раздел в документации для String Class , в котором есть что сказать по теме:
Методы поиска строк, такие как String.StartsWith и String.IndexOf, также могут выполнять сравнение строк с учетом культуры или порядковых строк. Следующий пример иллюстрирует различия между порядковыми и чувствительными к культуре сравнениями с использованием метода IndexOf. В культурно-чувствительном поиске, в котором текущей культурой является английский (США), подстрока "oe" соответствует лигатуре "œ" Поскольку мягкий дефис (U + 00AD) является символом нулевой ширины, поиск обрабатывает мягкий дефис как эквивалент пустого и находит совпадение в начале строки. Порядковый поиск, с другой рука, не находит соответствия ни в одном случае.
Я выделил соответствующую часть, но я также помню пост в блоге об этой проблеме некоторое время назад, но мой Google-Fu сегодня меня подводит.
Проблема здесь в том, что IndexOf и Replace используют разные методы для поиска текста.
Принимая во внимание, что IndexOf будет рассматривать мягкий дефис как "не совсем там" и, таким образом, обнаружит два пробела с каждой стороны как "два соединенных пробела", метод Replace не будет и, следовательно, не удалит ни их. Следовательно, критерии присутствуют для продолжения цикла, но поскольку Replace не удаляет пробелы, которые соответствуют критериям, он никогда не завершится. Несомненно, в пространстве символов Unicode есть и другие подобные символы, которые имеют аналогичные проблемы, но это наиболее типичный случай, который я видел.
Есть как минимум два способа справиться с этим:
Вы можете использовать Regex.Replace, у которого, похоже, нет этой проблемы:
text = Regex.Replace(text, " +", " ");
Лично я бы, вероятно, использовал специальный символ пробела в Регулярном выражении, который равен \s
, но если вам нужны только пробелы, вышеприведенное должно помочь.
Вы можете явно попросить IndexOf использовать порядковое сравнение, которое не сработает из-за текста, который ведет себя как ... ну ... текст:
index = text.IndexOf(" ", StringComparison.Ordinal);