#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";