Не удается выполнить поиск символа новой строки в строке

#c# #string #newline #indexof

Вопрос:

В C# я ищу индекс строки внутри строки — в частности, индекс, в котором находится символ новой строки ( n ).

Задана строка с разрывами строк Windows ( rn ):

Если я буду искать "n" , это даст мне -1. Если я ищу "rn" , я получаю результат. Если я ищу 'n' как персонаж, я получаю результат.

Учитывая строку с разрывами строк Unix ( n ), я получаю результат.

 string s = "hellornworld";

Console.WriteLine(@"rn index: "   s.IndexOf("rn")); // 5
Console.WriteLine(@"n index as string: "   s.IndexOf("n")); // -1
Console.WriteLine(@"n index as char: "   s.IndexOf('n')); // 6


s = "hellonworld";

Console.WriteLine(@"n index as string: "   s.IndexOf("n")); // 5
Console.WriteLine(@"n index as char: "   s.IndexOf('n')); // 5
 

Я понимаю, что разрывы строк-это два символа, и если бы я использовал StreamReader или файл.Прочитанные строки или что-то в этом роде, тогда это будет обработано автоматически, и я их потеряю.

Я думал n , что это сама по себе допустимая строка, и она rn , хотя и особенная, все же представляет собой два отдельных и различных символа в строке. Но это говорит мне об обратном.

Я могу сделать индексацию символа вместо строки ( 'n' вместо "n" ), но мне действительно хотелось бы знать, почему это происходит, чтобы я мог это спланировать.

Редактировать

К вашему сведению: Только что обнаружил, что преобразование строки в a Span дает правильный результат. Не уверен, что это связано с накладными расходами, поэтому я не знаю, как это соотносится с порядковым решением — я предполагаю, что порядковый номер лучше:

 Console.WriteLine(@"n index as string Ordinal: " 
      s.IndexOf("n", StringComparison.Ordinal)); // 6

Console.WriteLine(@"n index as Span: "
      s.AsSpan().IndexOf("n".AsSpan())); // 6

Console.WriteLine(@"n index as string with s.AsSpan(): " 
      s.AsSpan().IndexOf("n")); // 6
 

Комментарии:

1. Я запустил ваш код и получил другой результат. индексы по строкам: 5 6 6 5 5

2. @OmarAbdelBari Да, это приятно знать — в моем случае я пытаюсь сохранить разрывы строк данных, на которые я смотрю, поэтому я не хочу использовать системный разделитель в случае, если в определенных файлах есть некоторые окончания в стиле Unix-я просто пытался подсчитать разрывы строк в куче файлов, когда заметил это.

3. @NigelBess Это действительно интересно — я только что изменил свой проект на .NET Core 3.1 вместо .NET 5, и он делает 5 6 6 5 5, как у вас — я предполагаю, что вы запустили его на 3.1? Может быть, это ошибка фреймворка (или функция, которая не привлекла никакого внимания). Если я не найду ответа, я отправлю это в Microsoft.

4. @Joe Enos Я запустил его на .NET 6 предварительный просмотр 7 на самом деле lol

5. @JoeEnos Я только что изменил проект на .NET 5 и получил тот же результат, что и вы. -1 для второго вывода

Ответ №1:

В .Net 5.0 произошли изменения с библиотеками глобализации для Windows. В предыдущих версиях NLS использовался в Windows, а ICU-в Unix. .Net 5 использует ICU на обоих, чтобы сделать кросс-платформенную разработку последовательной, за счет удивления разработчиков Windows (вздох). В связи с этим изменением вы должны пройти StringComparison.Ordinal , чтобы найти новую строку в строке.

Обратите внимание, что это также может зависеть от версии Windows (двойной вздох), поскольку Windows 10 мая 2019 года включает библиотеку ICU и более ранние версии, которые этого не вызовут .Сеть 5, чтобы вернуться к NLS.

См.Эту статью от корпорации Майкрософт. В этой статье содержится более подробная информация о затронутых API.

Комментарии:

1. Это безумие — не похоже, что это была очень хорошая идея. Мне нравится, что в статье практически такой же образец, как и у меня. Клянусь, я его не крал 🙂

2. @JoeEnos К сожалению, также затронуто множество API-интерфейсов. Я действительно думаю, что это прискорбно, что они внесли изменение в глобализацию, которое заключается в отказе от участия, а не в согласии. Если вам не нужно/вы не хотите заниматься глобализацией, вы все равно будете наказаны. Возможно, им также следовало изменить значение по умолчанию для одного аргумента IndexOf Ordinal и разбить его . Вместо этого сеть совместима с Unix.

3. Это не безумие, это глупо. Если бы я этого хотел, я бы хотел StringComparison.Magic

4. @Кристианголлхардт StringComparison.LetMeTellYouWhatIThinkYouWantRatherThanWhatYouToldMeToDo

Ответ №2:

Вы можете использовать System.Environment.NewLine в своем сценарии, который является условным свойством для символа новой строки, в зависимости от операционной системы. Проверьте здесь.

В Windows: "rn" .
На unix-платформах: "n" .

 using System;
string s = "hello"   Environment.NewLine   "world";