Что обычно лучше всего использовать - StringComparison.OrdinalIgnoreCase или StringComparison.InvariantCultureIgnoreCase?

162

У меня есть такой код:

If key.Equals("search", StringComparison.OrdinalIgnoreCase) Then
    DoSomething()
End If

Меня не волнует дело. Должен ли я использовать OrdinalIgnoreCase, InvariantCultureIgnoreCaseили CurrentCultureIgnoreCase?

Дейв Хейнс
источник
2
Проверьте это действительно полезно для этой темы. Мое предложение использовать ordianlignorecase для сравнения. blogs.msdn.com/b/noahc/archive/2007/06/29/…
UmaMaheswaran
Примите во
Майкл
В целом, это зависит от того, что вы сравниваете. В частности, если это зависит от культуры ввода пользователя или внутренних вещей. Вы не хотите, чтобы культура ПК испортила сравнение внутренних строк кода.
Nyerguds

Ответы:

180

В новых .Net Docs теперь есть таблица, которая поможет вам решить, что лучше всего использовать в вашей ситуации.

Из MSDN " Новые рекомендации по использованию строк в Microsoft .NET 2.0 "

Описание: Владельцам кода, ранее использующим InvariantCultureдля сравнения строк, регистр и сортировку, настоятельно рекомендуется использовать новый набор Stringперегрузок в Microsoft .NET 2.0. В частности, данные, предназначенные для того, чтобы быть независимыми от культуры и не относящимися к языку, должны начинать указывать перегрузки, используя либо новое членство, StringComparison.Ordinalлибо StringComparison.OrdinalIgnoreCaseчлены StringComparison. Они обеспечивают побайтовое сравнение, подобное тому, strcmpкоторое не только позволяет избежать ошибок в лингвистической интерпретации по существу символических строк, но и обеспечивает лучшую производительность.

Роберт Тейлор
источник
126
Чтобы привести пример, где они различаются, рассмотрим две строки "Straße"и "STRASSE". При использовании OrdinalIgnoreCaseна Equalsотдачу false, а InvariantCultureIgnoreCaseговорит , что они равны.
Джеппе Стиг Нильсен
2
Обновленная ссылка: docs.microsoft.com/en-us/dotnet/standard/base-types/…
Охад Шнайдер
64

Все это зависит

Сравнивать строки в юникоде сложно:

Реализация поиска и сравнения строк Unicode в программном обеспечении для обработки текста должна учитывать наличие эквивалентных кодовых точек. В отсутствие этой функции пользователи, ищущие определенную последовательность кодовых точек, не смогут найти другие визуально неразличимые глифы, которые имеют другое, но канонически эквивалентное представление кодовых точек.

см .: http://en.wikipedia.org/wiki/Unicode_equivalence


Если вы пытаетесь сравнить 2 строки юникода без учета регистра и хотите, чтобы они работали ВЕЗДЕ , у вас возникла невозможная проблема.

Классическим примером является турецкий i , который в верхнем регистре становится İ (обратите внимание на точку)

По умолчанию .NET Framework обычно использует CurrentCulture для функций, связанных со строками, за очень важным исключением - .Equalsиспользуется порядковое (побайтное) сравнение.

Это приводит к тому, что различные строковые функции ведут себя по-разному в зависимости от культуры компьютера.


Тем не менее, иногда мы хотим «общего назначения», без учета регистра, сравнения.

Например, вы можете захотеть, чтобы сравнение строк велось одинаково, независимо от того, на каком компьютере установлено приложение.

Для этого у нас есть 3 варианта:

  1. Установите явную культуру и выполните сравнение без учета регистра, используя правила эквивалентности Юникода.
  2. Установите для культуры значение Инвариантная культура и выполняйте сравнение без учета регистра, используя правила эквивалентности Юникода.
  3. Используйте OrdinalIgnoreCase, который будет вводить строку в верхнем регистре с помощью InvariantCulture, а затем выполнять побайтовое сравнение.

Правила эквивалентности Unicode сложны, что означает, что использование метода 1) или 2) более затратно, чем OrdinalIgnoreCase. Тот факт, что OrdinalIgnoreCaseне выполняется какая-либо специальная нормализация Юникода, означает, что некоторые строки, которые отображаются одинаково на экране компьютера, не будут считаться идентичными. Например: "\u0061\u030a"и "\u00e5"оба рендера. Однако в порядковом сравнении будет считаться другим.

То, что вы выберете, во многом зависит от приложения, которое вы создаете.

  • Если бы я писал бизнес-приложение, которое использовалось только турецкими пользователями, я бы обязательно использовал метод 1.
  • Если бы мне просто потребовалось простое «поддельное» сравнение без учета регистра, например, имя столбца в БД, которое обычно является английским, я бы, вероятно, использовал метод 3.

У Microsoft есть свои рекомендации с четкими рекомендациями. Тем не менее, очень важно понять понятие эквивалентности Юникода, прежде чем подходить к этим проблемам.

Кроме того, имейте в виду, что OrdinalIgnoreCase - это особый вид зверя, который выбирает и выбирает немного порядкового сравнения с некоторыми смешанными в лексикографических аспектах. Это может сбивать с толку.

Сэм Шафран
источник
Что если я создаю турецкое приложение, которое будет использоваться только турецкими пользователями, но я хочу, чтобы «ayakkabı» и «ayakkabi» были равны, есть ли способ? Когда люди печатают на своих телефонах, большинство из них по умолчанию используют английскую клавиатуру, и им все равно, набирают ли они «ı» или «i».
Волкан Сен
4

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

Bullines
источник
1

Это зависит от того, что вы хотите, хотя я бы уклоняться от InvariantCulture , если вы не очень уверены , что вы никогда не хотите , чтобы локализовать код для других языков. Вместо этого используйте CurrentCulture.

Кроме того, OrdinalIgnoreCase должен учитывать числа, которые могут или не могут быть тем, что вы хотите.

Джоэл Коухорн
источник
1
Вы когда-нибудь писали код VB6 в смешанной среде? Вы можете создать код, который будет компилироваться на ПК с французской локалью, но не будет компилироваться на ПК с английской локалью, потому что любые числа, хранящиеся в ресурсах формы, используют формат текущей локали. Я бы сказал, что вам нужно придерживаться противоположного подхода: будьте очень осторожны при использовании текущей культуры. Всегда думайте о том, будет ли ваша система работать, когда ее данные перемещаются между культурами. То же самое и с часовыми поясами.
Вим Коенен
Я согласен с ответом «все зависит». хотя не следите за битом "уважение чисел"?
Сэм Шафран
-1

Очень простой ответ: если вы не используете турецкий язык, вам не нужно использовать InvariantCulture.

Смотрите следующую ссылку:

В C # в чем разница между ToUpper () и ToUpperInvariant ()?

TheMoot
источник
5
Этот ответ может быть простым, но он также очень неправильный. Турецкое «Я» является лишь примером , есть еще много возможных подводных камней.
Охад Шнайдер
Какие еще подводные камни? Я просто знаю о турецком проблемном случае.
HelloWorld
Да, кроме турецкого есть азербайджанский. Но это все.
Джим Балтер