Верхний и нижний регистр

При сравнении без учета регистра более эффективно преобразовывать строку в верхний или нижний регистр? Имеет ли это значение?

в этом посте SO предлагается, чтобы С# был более эффективным с ToUpper, потому что "Microsoft оптимизировала его таким образом". Но я также прочитал этот аргумент, что преобразование ToLower против ToUpper зависит от того, что в ваших строках больше, и что обычно строки содержат больше символов нижнего регистра, что делает ToLower более эффективным.

В частности, я хотел бы знать:

  • Есть ли способ оптимизировать ToUpper или ToLower так, чтобы один был быстрее другого?
  • Быстрее ли сравнивать строки в верхнем или нижнем регистре без учета регистра и почему?
  • Существуют ли какие-либо среды программирования (например, C, С#, Python и т.д.), Где один случай явно лучше другого и почему?

Ответ 1

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

MSDN имеет некоторые отличные рекомендации по обработке строк. Вы также можете проверить, что ваш код проходит турецкий тест.

EDIT: Обратите внимание, что Нил комментирует порядковые сравнения без учета регистра. Все это царство довольно мутное: (

Ответ 2

От Microsoft на MSDN:

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

Recommendations for String Usage

Почему? От Microsoft:

Нормализуйте строки в верхний регистр

Существует небольшая группа символов, которые при преобразовании в нижний регистр не могут совершать поездки в оба конца.

Каков пример такого персонажа, который не может совершить путешествие туда и обратно?

  • Начало: символ греческого Ро (U + 03f1) & # x03f1;
  • Прописные буквы: прописной греческий язык Ро (U + 03a1) & # x03a1;
  • Строчные: Маленький греческий Ро (U + 03c1) & # x03c1;

ϱ, Ρ, ρ

.NET Fiddle

Original: ϱ
ToUpper: Ρ
ToLower: ρ

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

Поэтому, если вам нужно выбрать один, выберите Прописные буквы.

Ответ 3

Согласно MSDN, более эффективно передавать строки и сообщать об этом, чтобы игнорировать случай:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) эквивалентно (, но быстрее), вызывающему

String.Compare(ToUpperInvariant (strA), ToUpperInvariant (strB), StringComparison.Ordinal).

Эти сравнения все еще очень быстрые.

Конечно, если вы сравниваете одну строку снова и снова, это может не выполняться.

Ответ 4

На основе строк, имеющих тенденцию иметь более строчные записи, ToLower теоретически должен быть быстрее (много сравнений, но несколько назначений).

В C или при использовании индивидуально доступных элементов каждой строки (например, строк C или строкового типа STL в С++) это фактически сравнение байтов, поэтому сравнение UPPER ничем не отличается от lower.

Если вы были подлыми и загрузили свои строки в массивы long вместо этого, вы бы получили очень быстрое сравнение по всей строке, потому что он мог сравнивать 4 байта за раз. Однако время загрузки может сделать его нецелесообразным.

Зачем вам нужно знать, что быстрее? Если вы не выполняете метрическую нагрузку сравнений, один, выполняющий пару циклов быстрее, не имеет отношения к скорости общего выполнения и звучит как преждевременная оптимизация:)

Ответ 5

Microsoft оптимизировала ToUpperInvariant(), а не ToUpper(). Разница в том, что инвариант более дружелюбен к культуре. Если вам нужно делать нечувствительные к регистру сравнения строк, которые могут различаться в культуре, используйте Invariant, в противном случае производительность инвариантного преобразования не должна иметь значения.

Я не могу сказать, работает ли ToUpper() или ToLower() быстрее. Я никогда не пробовал, так как у меня никогда не было ситуации, в которой производительность значила.

Ответ 6

Если вы выполняете сравнение строк в С#, значительно быстрее использовать .Equals() вместо преобразования обеих строк в верхний или нижний регистр. Еще один большой плюс для использования .Equals() заключается в том, что больше памяти не выделяется для 2 новых строк верхнего/нижнего регистра.

Ответ 7

Это действительно не должно иметь значения. С символами ASCII это определенно не имеет значения - это всего лишь несколько сравнений и немного флип для любого направления. Unicode может быть немного сложнее, так как есть некоторые символы, которые меняют случай по странным путям, но там действительно не должно быть никакой разницы, если ваш текст не заполнен этими специальными символами.

Ответ 8

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

Ответ 9

Зависит. Как указано выше, простой только ASCII, его идентичный. В .NET читайте и используйте String.Compare, это правильно для i18n материала (языки культур и unicode). Если вы знаете что-нибудь о вероятности ввода, используйте более распространенный случай.

Помните, что если вы выполняете несколько строк, то длина - отличный первый дискриминатор.

Ответ 10

Если вы имеете дело с чистым ASCII, это не имеет значения. Это просто OR x, 32 против AND x, 224. Unicode, я понятия не имею...