Разница между InvariantCulture и порядком сравнения строк - PullRequest
491 голосов
/ 29 января 2009

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

Ответы [ 9 ]

274 голосов
/ 29 января 2009

InvariantCulture

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

Порядковый

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


На 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).

210 голосов
/ 20 ноября 2013

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

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

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

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

85 голосов
/ 25 февраля 2014

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

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

И наконец:

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

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

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

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

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

И по InvariantCulture: "0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"

28 голосов
/ 11 июня 2014

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

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));
}
26 голосов
/ 03 июня 2010

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

5 голосов
/ 12 июля 2015

Вот пример, где сравнение равенства строк с использованием 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 будет ложным, а equals2 будет истинным.

2 голосов
/ 29 ноября 2017

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

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

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1
0 голосов
/ 18 февраля 2009

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

...