someString.IndexOf (someString) возвращает 1 вместо 0 under.NET 4
мы недавно обновили все наши проекты с .NET 3.5 до .NET 4. Я столкнулся с довольно странной проблемой в отношении string.IndexOf()
.
мой код, очевидно, делает что-то немного другое, но в процессе исследования проблемы, я обнаружил, что вызов IndexOf()
на строку с собой возвращается 1 вместо 0.
Другими словами:
string text = "xADx2D"; // problem happens with "-dely N.China", too;
int index = text.IndexOf(text); // see update note below.
дал мне индекс 1, а не 0. Несколько вещей, чтобы отметить об этом проблема:
проблемы, похоже, связаны с этими дефисами (первый символ-мягкий дефис Unicode, второй-обычный дефис).
Я дважды проверил, это не происходит в .NET 3.5, но делает в .NET 4.
изменение
IndexOf()
для выполнения порядкового сравнения исправляет проблему, поэтому по какой-то причине первый символ игнорируется по умолчаниюIndexOf
.
тут кто-нибудь знает, почему это происходит?
EDIT
Извините, ребята, сделал немного материала на оригинальном посту и получил скрытый тире там дважды. Я обновил строку, это должно возвращать индекс 1 вместо 2, пока вы вставляете его в правильный редактор.
обновление:
изменил исходную строку задачи на ту, где каждый фактический символ четко виден (используя экранирование). Это упрощает вопрос немного.
3 ответа:
ваша строка состоит из двух символов: a мягкий перенос (кодовая точка Unicode 173) и тире (кодовая точка Unicode 45).
Wiki: согласно стандарту Unicode, мягкий дефис не отображается, если линия не нарушена в этой точке.
при использовании
"\xAD\x2D".IndexOf("\xAD\x2D")
в .NET 4, похоже, игнорируется, что вы ищете мягкий дефис, возвращая начальный индекс 1 (индекс\x2D
). В .NET 3.5 это возвращает 0.больше удовольствия, если вы запустите этот код (так когда только ищу мягкий дефис):
string text = "\xAD\x2D"; string shy = "\xAD"; int i1 = text.IndexOf(shy);
затем
i1
становится 0, независимо от используемой версии .NET. Результатtext.IndexOf(text);
действительно меняется, что на первый взгляд выглядит как ошибка для меня.насколько я могу отследить через фреймворк, более старые версии .NET используют InternalCall до
IndexOfString()
(Я не могу понять, к какому API вызов, который идет), в то время как из .NET 4 A QCall доInternalFindNLSStringEx()
сделано, что в свою очередь вызываетFindNLSStringEx()
.проблема (я действительно не могу понять, если это намеренное поведение) действительно происходит при вызове
FindNLSStringEx
:LPCWSTR lpStringSource = L"\xAD\x2D"; LPCWSTR lpStringValue = L"\xAD"; int length; int i = FindNLSStringEx( LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, lpStringSource, -1, lpStringValue, -1, &length, NULL, NULL, 1); Console::WriteLine(i); i = FindNLSStringEx( LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, lpStringSource, -1, lpStringSource, -1, &length, NULL, NULL, 1); Console::WriteLine(i); Console::ReadLine();
выводит 0, а затем 1. Обратите внимание, что
length
, параметр out, указывающий длину найденной строки, равен 0 после первого вызова и 1 после второго; мягкий дефис считается имеющим длину 0.обходной путь заключается в использовании
text.IndexOf(text, StringComparison.OrdinalIgnoreCase);
, как вы отметили. Это делает QCall вInternalCompareStringOrdinalIgnoreCase()
, который, в свою очередь, называетFindStringOrdinal()
, которая возвращает 0 для обоих случаев.
похоже, это ошибка в. NET4, и новые изменения вернулись в . NET4 Beta1 к предыдущей версии такой же как .NET 2.0/3.0/3.5.
что нового в BCL в .NET 4.0 CTP (блоги MSDN):
изменения Безопасности строк в .NET 4
частичные совпадающие перегрузки по умолчанию в системе.Строка (StartsWith, EndsWith, IndexOf и LastIndexOf) имеет было изменено, чтобы быть агностиком культуры (порядковый номер) по умолчанию.
это изменение повлияло на поведение
String.IndexOf
метод путем изменения их для выполнения порядкового (байт-для-байт) сравнения по умолчанию будет изменен на использованиеCultureInfo.InvariantCulture
вместоCultureInfo.CurrentCulture
.обновление для .NET 4 Beta 1
чтобы поддерживать высокую совместимость между .NET 4 и предыдущими выпусками, мы решили отменить это изменение. Этот поведение частичных совпадающих перегрузок String по умолчанию и методов String и Char ToUpper и ToLower теперь ведут себя так же, как и в .NET 2.0/3.0/3.5. Изменение обратно к исходному поведению присутствует в .NET 4 Beta 1.
исправить измените метод сравнения строк на перегрузку, которая принимает
System.StringComparison
перечисление в качестве параметра, и указатьOrdinal
илиOrdinalIgnoreCase
.// string contains 'unicode dash' \x2D string text = "\xAD\x2D"; // woks in .NET 2.0/3.0/3.5 and .NET 4 Beta 1 and later // but seems be buggy in .NET 4 because of 'culture-sensitive' comparison int index = text.IndexOf(text); // fixed version index = text.IndexOf(text, StringComparison.Ordinal);
С документация (Курсив мой):
этот метод выполняет слово (чувствительный к регистру и культуре) поиск с использованием текущего языка и региональных параметров.
Ie. некоторые отдельные кодовые точки будут рассматриваться как равные.
что произойдет, если вы используете перегрузку, которая принимает
StringComparison
значение и передаютStringComparison.Ordinal
чтобы избежать культурных зависимостей?