Укажите порядок сортировки с помощью LC_COLLATE, чтобы строчные буквы были перед прописными

16

Учитывая файл:

$ cat file
1
a
C
B
2
c
3
A
b

По умолчанию sortбудет:

$ sort file
1
2
3
a
A
b
B
c
C

С LC_COLLATE=Cтаким образом отсортирует заглавные буквы перед строчными:

$ LC_COLLATE=C sort file
1
2
3
A
B
C
a
b
c

Можно ли получить сортировку для обратного упорядочения регистра, то есть цифры, строчные и прописные?

iiSeymour
источник

Ответы:

8

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

Подавляющее большинство локалей не задают свой собственный порядок сортировки, а скорее копируют определенный порядок сортировки, /usr/share/i18n/locales/iso14651_t1_commonтак что это то, что вы захотите редактировать. Вместо того, чтобы изменять порядок сортировки почти каждой локали, изменяя оригинал iso14651_t1_common, я предлагаю вам сделать копию. Подробная информация о том, как работает порядок сортировки и как создать пользовательский языковой стандарт в вашем $HOMEкаталоге без корневого доступа, содержится в этом ответе на аналогичный вопрос .

Посмотрите, как aи как Aони упорядочены на основе их записей в iso14651_t1_common:

<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a
<U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A

bи Bпохожи:

<U0062> <b>;<BAS>;<MIN>;IGNORE # 233 b
<U0042> <b>;<BAS>;<CAP>;IGNORE # 550 B

Мы видим, что на первом проходе оба aи Aимеют символ сортировки <a>, а оба bи Bимеют символ сортировки <b>. Так как <a>появляется раньше <b>в iso14651_t1_common, aи Aсвязаны до bи B. Второй проход не разрывает связи, потому что все четыре символа имеют символ сортировки <BAS>, но во время третьего прохода связи разрешаются, потому что символ сортировки для строчных букв <MIN>появляется в строке 3467, перед символом сортировки для прописных букв <CAP>(строка 3488) , Таким образом, порядок сортировки заканчивается как a, A, b, B.

Поменяв местами первый и третий символы сортировки, можно отсортировать буквы сначала по регистру (ниже, чем по верху), затем по акценту ( <BAS>означает без акцента ), а затем по алфавиту. Однако оба <MIN>и <CAP>идут перед цифровыми цифрами, так что это будет иметь нежелательный эффект, заключаясь в том, что цифры ставятся после букв.

Самый простой способ сохранить цифры вначале, когда все строчные буквы идут раньше всех заглавных букв, состоит в том, чтобы принудительно связать все буквы во время первого сравнения, установив их все равными <a>. Чтобы убедиться, что они сортируются в алфавитном порядке в пределах регистра, измените последний символ сортировки с IGNOREтекущего первого символа сортировки. Следуя этой схеме, aстанет:

<U0061> <a>;<BAS>;<MIN>;<a> # 198 a

A станет:

<U0041> <a>;<BAS>;<CAP>;<a> # 517 A

b станет:

<U0062> <a>;<BAS>;<MIN>;<b> # 233 b

B станет:

<U0042> <a>;<BAS>;<CAP>;<b> # 550 B

и так далее для остальных букв.

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

beandip
источник
6

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

При этом также будут учитываться не алфавитно-цифровые и даже непечатаемые символы, но если вы не хотите, чтобы были параметры -dи -i(описано в man sort) отключить их.

Тем не менее, он, вероятно, будет плохо работать с многобайтовым вводом, например, UTF-8 с не-ASCII символами.

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

tr 'a-zA-Z' 'A-Za-z' < file | LC_ALL=C sort | tr 'a-zA-Z' 'A-Za-z'
Law29
источник
2

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

Тем не менее, я никогда не делал этого, но вы, возможно, захотите взглянуть на man-страницы localedef (1) и locale (5), чтобы понять, как определяются языковые стандарты и в конечном итоге определить свой собственный.

Также не забывайте, что, если есть какие-либо диакритические знаки или специальные символы, язык C не будет обрабатывать их так, как вы этого хотите. Например, он не будет ставить áрядом aили Łрядом L. В таких случаях родная локаль языка, вероятно, будет лучшей отправной точкой.

Алоис Махдал
источник
0

Я считаю, что ответ без необходимости изменения LC_COLLATE (то есть, оставив функцию в качестве поведения по умолчанию):

сортировать -f файл

Это работает в Linux; Пожалуйста, обратитесь к разделу справки для команды, если вы используете Unix и используете другую версию. -f определяется как игнорирующий регистр.

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

1m.0g
источник
-1
LC_COLLATE="en_US.UTF-8" sort file
unxnut
источник
Это не сортирует строчные перед прописными? ideone.com/Gtyg4Z
iiSeymour
Хм, в моем случае это было сделано на вашем примере.
unxnut
4
@unxnut Это неверно. Без точки с запятой команда задает среду для sort, но с точкой с запятой переменная является локальной для оболочки и не влияет на поведение sort. Точка с запятой может быть сохранена как есть, если переменная также экспортируется, но это повлияет и на другие команды.
Андерс Шеквист