ToUpperInvariant() — неправильно ли MSDN рекомендует?

В Рекомендации по использованию строк в .NET Framework, StringComparison OrdinalIgnoreCase рекомендуется для путей к файлам без учета регистра. (Назовем это Утверждение А.)

Я могу с этим согласиться, потому что я могу создать два файла в одном каталоге:

é.txt
é.txt

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

Если бы действовало сравнение инвариантных культур (а не порядковое сравнение), NTFS не разрешила бы эти файлы, потому что в той же статье объясняется, что в инвариантных культурах a + ̊ = å

Но в статье на String.ToUpperInvariant() есть другая рекомендация: (Утверждение Б.)

Если вам нужна строчная или прописная версия идентификатора операционной системы, например имени файла, именованного канала или раздела реестра, используйте методы ToLowerInvariant или ToUpperInvariant.

Мне нужно создать коллекцию путей к файлам (фактически HashSet) для обнаружения дубликатов. Так что, если я буду подчиняться инструкции B при создании карты, я могу закончить с ложными срабатываниями, потому что вышеупомянутые имена файлов é.txt и é.txt будут считаться одним. Правильно ли я понимаю, что утверждение B, найденное в MSDN, вводит в заблуждение? Или я что-то упускаю?

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

Обновлять:

В заявлении B, кажется, есть еще одна проблема: ToLowerInvariant() на самом деле нельзя использовать. Причина (цитирую статью с рекомендациями): DO: Use ToUpperInvariant rather than ToLowerInvariant when normalizing strings for comparison. Фактическая причина: There is a small range of characters that do not roundtrip, and going to lowercase will make these characters unavailable. (источник)


person miroxlav    schedule 23.09.2015    source источник
comment
Я не совсем уверен, что версия идентификатора операционной системы в нижнем или верхнем регистре должна совпадать с однозначным сопоставлением идентификатора операционной системы с версией в нижнем или верхнем регистре. Это также может означать сопоставление идентификатора операционной системы с неуникальной версией нижнего или верхнего регистра, которая будет работать одинаково независимо от языкового стандарта системы.   -  person O. R. Mapper    schedule 23.09.2015
comment
OT, но кто знает, что делает ваша библиотека: NTFS также допускает :, * или ? в именах файлов. Просто винда его не поддерживает. Создать такие файлы в NTFS под Linux довольно просто.   -  person Thomas Weller    schedule 23.09.2015
comment
@O.R.Mapper - хороший способ прочтения этого утверждения ... В этом контексте это выглядит логично. С другой стороны, они могли либо не упоминать имена файлов, либо добавить короткое примечание о (не)уникальности.   -  person miroxlav    schedule 23.09.2015


Ответы (1)


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

Правильный способ сравнения строк без учета регистра — использовать один из нечувствительных к регистру параметров StringComparison (вы это знаете).

Правильный способ использования структуры данных без учета регистра — использовать один из StringComparer.*IgnoreCase. Например:

new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)

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

Если вам нужна строчная или прописная версия идентификатора операционной системы

Вам не нужна такая вещь. Это утверждение не относится к вашему случаю.

person usr    schedule 23.09.2015
comment
Таким образом, в случае имен файлов NTFS это означает new HashSet<string>(StringComparer.OrdinalIgnoreCase) (или просто OrdinalCase, в зависимости от того, как в конкретном случае переключается чувствительность к регистру NTFS). - person miroxlav; 23.09.2015
comment
Я не знаю, какое сравнение использует NTFS. Его можно настроить. На каждом томе NTFS есть скрытый файл, в котором хранится таблица соответствия регистра Unicode. Я думаю, это может быть произвольно. Не уверен, что это на практике. - person usr; 23.09.2015
comment
Да, я это знаю... Это означает, что нам действительно может понадобиться что-то вроде NtfsIgnoreCase сравнения, работающего на основе содержимого этого скрытого $UpCase файла :) - person miroxlav; 23.09.2015
comment
См. этот мой ответ (для краткости: используйте OrdinalIgnoreCase для имен файлов). - person Lucas Trzesniewski; 24.09.2015
comment
@LucasTrzesniewski - я действительно видел это :), а также это и это важные вопросы и ответы. Наконец, я использовал Dictionary(Of T1, T2)(StringComparer.OrdinalIgnoreCase) для своих конкретных нужд. - person miroxlav; 24.09.2015