Разница между InvariantCulture и порядком сравнения строк

424

При сравнении двух строк в С# для равенства, в чем разница между InvariantCulture и сравнением ординалов?

  • 0
    Может быть, siao2.com/2004/12/29/344136.aspx ? (Гугл)
  • 2
    Для тех, кто использует String1.Equals(String2, StringComparison.Ordinal) , лучше использовать String1 == String2 который по своей сути является String1.Equals(String2) и по умолчанию это порядковое сравнение с учетом регистра.
Показать ещё 3 комментария
Теги:
string-comparison
ordinal

10 ответов

229
Лучший ответ

InvariantCulture

Использует "стандартный" набор порядков символов (a, b, c,... и т.д.). Это контрастирует с некоторыми конкретными локалями, которые могут сортировать символы в разных порядках ( "a-with-sharp" может быть до или после "a", в зависимости от локали и т.д.).

Порядковый

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


Там отличный образец в http://msdn.microsoft.com/en-us/library/e6883c06.aspx, который показывает результаты различных значений StringComparison. В конце он показывает (выдержки):

StringComparison.InvariantCulture:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is less than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

StringComparison.Ordinal:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is greater than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

Вы можете видеть, что, когда InvariantCulture дает (U + 0069, U + 0049, U + 00131), Порог выхода (U + 0049, U + 0069, U + 00131).

  • 20
    Порядковое сравнение смотрит на кодовые точки , а не байты.
  • 121
    Я чувствую, что это полезная информация, но на самом деле не отвечает на вопрос. При определении равенства двух строк, есть ли причина использовать InvarintCulture вместо Ordinal? Кажется, что InvariantCulture будет использоваться для сортировки строк, а Ordinal должен использоваться для проверки на равенство (нас не волнует, что ударение-a идет до или после a, оно просто другое). Хотя я сам немного не уверен в этом.
Показать ещё 7 комментариев
150

Это имеет значение, например - есть вещь, называемая расширением символов

        var s1 = "Strasse";
        var s2 = "Straße";

        s1.Equals(s2, StringComparison.Ordinal);           //false

        s1.Equals(s2, StringComparison.InvariantCulture);  //true

С InvariantCulture символ ß расширяется до ss.

  • 1
    Отличается ли эта вещь также в некотором роде между Ordinal и InvariantCulture ? Вот о чем идет речь в оригинальном вопросе.
  • 0
    Я думаю, что это так :) stackoverflow.com/a/20085208/210336
Показать ещё 5 комментариев
55

Указание на Рекомендации по использованию строк в .NET Framework:

  • Используйте StringComparison.Ordinal или StringComparison.OrdinalIgnoreCase для сопоставления в качестве безопасного по умолчанию для сопоставления строк, не связанных с культурой.
  • Для повышения производительности используйте сравнения с StringComparison.Ordinal или StringComparison.OrdinalIgnoreCase.
  • Используйте неязыковые значения StringComparison.Ordinal или StringComparison.OrdinalIgnoreCase вместо строковых операций на основе CultureInfo.InvariantCulture, если сравнение лингвистически неуместно (например, символическое).

И наконец:

  • Не используйте строковые операции на основе StringComparison.InvariantCulture в большинстве случаев. Одним из немногих исключений является то, что вы сохраняете лингвистически значимые, но культурно агностические данные.
54

Другое удобное различие (на английском языке, где акценты являются необычными) заключается в том, что сравнение InvariantCulture сначала сравнивает целые строки с учетом регистра без учета регистра, а затем, если необходимо (и запрашивается), различается в каждом случае после первого сравнения только с отдельными буквами. (Разумеется, вы также можете провести сравнение без учета регистра, которое не будет различать в зависимости от случая.) Исправлено: Акцентированные буквы считаются еще одним ароматом одних и тех же букв и сначала сравнивается строка игнорируя акценты, а затем учитывая их, если общие буквы совпадают (как и в случае с другим случаем, за исключением того, что в конечном счете игнорируются в случае нечувствительности к регистру). Эти группы акцентируют версии одного и того же слова рядом друг с другом, а не полностью разделяются при первой разнице акцентов. Это порядок сортировки, который вы обычно находите в словаре, с заглавными словами, которые появляются рядом с их нижестоящими эквивалентами, а буквы с акцентом находятся рядом с соответствующей безударной буквой.

Сравнение ординалов строго сравнивается с числовыми значениями символов, останавливаясь при первом различии. Этот вид заглавных букв полностью отделен от букв в нижнем регистре (и буквы с акцентом, предположительно, отделенные от них), поэтому заглавные слова будут сортироваться в никуда рядом с их младшими эквивалентами.

InvariantCulture также считает, что капиталы больше, чем в нижнем регистре, тогда как Ординал считает капиталы меньше, чем нижестоящие (сохранение ASCII с предыдущих дней до того, как компьютеры имели строчные буквы, заглавные буквы были выделены первыми и, следовательно, имели более низкие значения, чем строчные буквы, добавленные позже).

Например, по ординалу: "0" < "9" "A" "Ab" < "Z" "a" "aB" "ab" "z" "& Aacute;" < "& Aacute; b" < "& Aacute;" < "& Aacute; б"

И с помощью InvariantCulture: "0" & ​​lt; "9" "a" "A" "& Aacute;" < "& Aacute;" < "ab" "aB" "Ab" < "& aacute; b" < "& Aacute; b" < "z" "Z"

  • 0
    Я еще раз взглянул на это и заметил несоответствие между примером InvariantCulture и моим объяснением обработки акцентированных символов. Пример выглядит верным, поэтому я исправил объяснение, чтобы оно было последовательным. Сравнение InvariantCulture не останавливается на первом различающемся акценте и, по-видимому, учитывает разницу в акценте на той же букве, если остальные строки совпадают, кроме ударений и регистра. Разница в акценте учитывается перед разницей в более раннем случае, поэтому «Ааба» <«ааба».
23

Инвариант - это лингвистически подходящий тип сравнения.
Ординал - это двоичный тип сравнения. (Быстрее)
См. http://www.siao2.com/2004/12/29/344136.aspx

21

Хотя вопрос о равенстве, для быстрой визуальной ссылки, здесь порядок некоторых строк сортируется с использованием нескольких культур, иллюстрирующих некоторые из особенностей там.

Ordinal          0 9 A Ab a aB aa ab ss Ä Äb ß ä äb ぁ あ ァ ア 亜 A
IgnoreCase       0 9 a A aa ab Ab aB ss ä Ä äb Äb ß ぁ あ ァ ア 亜 A
--------------------------------------------------------------------
InvariantCulture 0 9 a A A ä Ä aa ab aB Ab äb Äb ss ß ァ ぁ ア あ 亜
IgnoreCase       0 9 A a A Ä ä aa Ab aB ab Äb äb ß ss ァ ぁ ア あ 亜
--------------------------------------------------------------------
da-DK            0 9 a A A ab aB Ab ss ß ä Ä äb Äb aa ァ ぁ ア あ 亜
IgnoreCase       0 9 A a A Ab aB ab ß ss Ä ä Äb äb aa ァ ぁ ア あ 亜
--------------------------------------------------------------------
de-DE            0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜
IgnoreCase       0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜
--------------------------------------------------------------------
en-US            0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜
IgnoreCase       0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜
--------------------------------------------------------------------
ja-JP            0 9 a A A ä Ä aa ab aB Ab äb Äb ß ss ァ ぁ ア あ 亜
IgnoreCase       0 9 A a A Ä ä aa Ab aB ab Äb äb ss ß ァ ぁ ア あ 亜

Наблюдения:

  • de-DE, ja-JP и en-US сортировать одинаково
  • Invariant сортирует только ss и ß по-разному от трех вышеупомянутых культур
  • da-DK сортируется совсем по-другому.
  • флаг IgnoreCase имеет значение для всех выбранных культур

Код, используемый для создания таблицы выше:

var l = new List<string>
    { "0", "9", "A", "Ab", "a", "aB", "aa", "ab", "ss", "ß",
      "Ä", "Äb", "ä", "äb", "あ", "ぁ", "ア", "ァ", "A", "亜" };

foreach (var comparer in new[]
{
    StringComparer.Ordinal,
    StringComparer.OrdinalIgnoreCase,
    StringComparer.InvariantCulture,
    StringComparer.InvariantCultureIgnoreCase,
    StringComparer.Create(new CultureInfo("da-DK"), false),
    StringComparer.Create(new CultureInfo("da-DK"), true),
    StringComparer.Create(new CultureInfo("de-DE"), false),
    StringComparer.Create(new CultureInfo("de-DE"), true),
    StringComparer.Create(new CultureInfo("en-US"), false),
    StringComparer.Create(new CultureInfo("en-US"), true),
    StringComparer.Create(new CultureInfo("ja-JP"), false),
    StringComparer.Create(new CultureInfo("ja-JP"), true),
})
{
    l.Sort(comparer);
    Console.WriteLine(string.Join(" ", l));
}
  • 1
    Хммм - хорошо, приятно, что вы провели это исследование и опубликовали свои выводы, хотя я не совсем уверен, в чем ваша точка зрения. В любом случае, датский язык может быть не одной из «самых важных культур» (хотя 5 миллионов датчан действительно очень любят их культуру), но если вы добавите «aa» в качестве дополнительной тестовой строки, а «da-DK» в качестве дополнительная культура тестирования, вы увидите некоторые интересные результаты.
  • 1
    @RenniePet Спасибо за это. Я добавил датский, так как он сортируется совсем не так, как 3 другие культуры. (Так как смайлики, указывающие на иронию, кажутся не столь хорошо понятными в сети чтения английского языка, как я бы предположил, я удалил комментарий «наиболее важных культур». В конце концов, BCL не имеет CultureComparer который мы могли бы используйте для проверки. Для этой таблицы Danish культура (информация) оказалась очень важной.)
Показать ещё 2 комментария
7

Возможно http://www.siao2.com/2004/12/29/344136.aspx? (Гугл)

3

Вот пример, где сравнение равенства строк с использованием InvariantCultureIgnoreCase и OrdinalIgnoreCase не даст одинаковых результатов:

string str = "\xC4"; //A with umlaut, Ä
string A = str.Normalize(NormalizationForm.FormC);
//Length is 1, this will contain the single A with umlaut character (Ä)
string B = str.Normalize(NormalizationForm.FormD);
//Length is 2, this will contain an uppercase A followed by an umlaut combining character
bool equals1 = A.Equals(B, StringComparison.OrdinalIgnoreCase);
bool equals2 = A.Equals(B, StringComparison.InvariantCultureIgnoreCase);

Если вы запустите это, equals1 будет false, а equals2 будет true.

  • 0
    Просто чтобы добавить еще один подобный пример, но со строковыми литералами, если a="\x00e9" (e острый) и b="\x0065\x0301" (e в сочетании с острым акцентом), StringComparer.Ordinal.Equals(a, b) вернет false, а StringComparer.InvariantCulture.Equals(a, b) вернет true.
0

Не нужно использовать необычные unicode char exmaples, чтобы показать разницу. Вот один простой пример, который я обнаружил сегодня, что удивительно, состоящий только из символов ASCII.

В соответствии с таблицей ASCII 0 (0x48) при сравнении по порядку меньше, чем _ (0x95). InvariantCulture скажет обратное (код PowerShell ниже):

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1
-7

Всегда пытайтесь использовать InvariantCulture в тех строковых методах, которые принимают его как перегрузку. Используя InvariantCulture, вы находитесь в безопасности. Многие программисты .NET могут не использовать эту функцию, но если ваше программное обеспечение будет использоваться в разных культурах, InvariantCulture - чрезвычайно удобная функция.

  • 3
    Если ваше программное обеспечение не будет использоваться разными культурами, оно будет намного медленнее, чем Ordinal.
  • 4
    Я подумал о том, чтобы понизить голосование, потому что вы, конечно, не продумали свой случайный ответ. Хотя внутри это зерно истины. Если ваше приложение широко распространено в разных культурах ... Это, безусловно, не гарантирует ваших первых слов "Всегда пытайтесь использовать InvariantCulture", не так ли? Я удивлен, что вы не возвращались годами, чтобы отредактировать это сумасшествие после получения отрицательного голоса и, возможно, большего опыта.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню