Имея файл со всеми (печатаемыми) символами ascii:
$ printf '%b' "$(printf '\\U%x\n' {32..126})" > file
Это можно отсортировать (используя tr для сокращения длинного вывода до одной строки):
$ sort file | tr -d '\n'
!"#%&'()*+,-./:;<=>?@[\]^_`{|}~$0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
Показывает, что на компьютере Debian Buster с локалью en_US.utf8 сортировка по столбцам (для отдельных символов) сначала имеет все знаки препинания, затем цифры, а затем смешанные регистры букв. То есть: aAbB, строчные и заглавные буквы вместе.
Предположим, что это верно и это именно то, чего пользователь (я) хочет от сопоставления.
Однако в той же системе, без каких-либо других изменений, происходит следующее:
$ grep '[a-z]' file | tr -d '\n'
abcdefghijklmnopqrstuvwxyz
То есть диапазон a-z
преобразуется чем-то только в строчные буквы ASCII.
Кто выполняет перевод и как его можно контролировать или изменять?
Я не спрашиваю о том, что такое строчные буквы или что должно означать [az] или что кто-то хочет, чтобы это означало.
Я полагаю, что [a-z]
это диапазон, который начинается a
и заканчиваетсяz
в порядке сортировки.
Я понимаю, что некоторые другие пользователи хотят, чтобы это было [a-z]
то же самое, что и "строчные" в любой локали. И я мог бы "жить с этим" по умолчанию.
Но как я могу это контролировать и/или менять, если это необходимо? Где ручка, чтобы это изменить?
Нет, изменение файлов сортировки не помогает, что-то находится за пределами этого и навязывает личное мнение, что a [a-z]
должно означать ASCII-строчные символы всегда и во всех локациях.
решение1
Я прочитал то, чтоСостояния POSIX. Моя интерпретация такова: есть два неэквивалентных понятия:
- последовательность сортировки (последовательность сортировки)
- порядок сопоставления
Соответствующие фрагменты [выделено мной]:
Категория
LC_COLLATE
предоставляетпоследовательность сортировкиопределение многочисленных утилит в томе «Оболочка и утилиты» POSIX.1-2017 (ls
,sort
, и т. д.), сопоставление регулярных выражений (см. Регулярные выражения) и функцииstrcoll()
,strxfrm()
,wcscoll()
, иwcsxfrm()
в томе «Системные интерфейсы» POSIX.1-2017.Апоследовательность сортировкиопределение должно определять относительный порядок между элементами сортировки (символами и многосимвольными элементами сортировки) в локали. Этот порядок выражается в терминах значений сортировки; то есть, назначая каждому элементу одно или несколько значений сортировки (также известных как веса сортировки). […]
Ключевое
order_start
слово должно предшествоватьпорядок сопоставлениязаписи, а также определить количество весов для этогопоследовательность сортировкиопределение и другие правила сопоставления.
Theпорядок сопоставлениякак определено в этом разделе, влияет на интерпретацию выражений в скобках в регулярных выражениях (см. Выражение в скобках RE).
Для sort
сортировки важна последовательность, т. е. веса. Для grep '[a-z]'
сортировки важен порядок, т. е. порядок записей порядка сортировки.
К сожалению, только последовательность сортировкиопределено явно, поэтому нет четких указаний на то, что порядок сортировки представляет собой иную концепцию.
Последовательность сортировки
Относительный порядок сортировки элементов, определяемый настройкой категорииLC_COLLATE
в текущей локали. Последовательность сортировки используется для сортировки и определяется из весов сортировки, назначенных каждому элементу сортировки. При отсутствии весов последовательность сортировки — это порядок, в котором сортировочные элементы указаны междуorder_start
иorder_end
ключевыми словами вLC_COLLATE
категории.
В моем Debian 9, когда дело доходит до LC_COLLATE
, многие локали в конечном итоге ссылаются на iso14651_t1_common
(ie /usr/share/i18n/locales/iso14651_t1_common
). Соответствующий фрагмент файла выглядит так:
<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a <U00AA> <a>;<PCL>;<EMI>;IGNORE # 199 ª <U00E1> <a>;<ACA>;<MIN>;IGNORE # 200 á […] <U0062> <b>;<BAS>;<MIN>;IGNORE # 233 b <U0253> <b>;<CRL>;<MIN>;IGNORE # 234 ɓ <U1E03> <b>;<PCT>;<MIN>;IGNORE # 235 ḃ […] <U007A> <z>;<BAS>;<MIN>;IGNORE # 507 z <U017A> <z>;<ACA>;<MIN>;IGNORE # 508 <z'> <U017E> <z>;<CAR>;<MIN>;IGNORE # 509 <z<> […] <U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A <U00C1> <a>;<ACA>;<CAP>;IGNORE # 518 Á <U00C0> <a>;<GRA>;<CAP>;IGNORE # 519 À […] <U0042> <b>;<BAS>;<CAP>;IGNORE # 550 B <U1E02> <b>;<PCT>;<CAP>;IGNORE # 551 <B.> <U1E04> <b>;<BPT>;<CAP>;IGNORE # 552 Ḅ […] <U005A> <z>;<BAS>;<CAP>;IGNORE # 813 Z <U0179> <z>;<ACA>;<CAP>;IGNORE # 814 <Z'> <U017D> <z>;<CAR>;<CAP>;IGNORE # 815 <Z<>
Этопорядок сопоставления. [a-z]
не содержит A
, поскольку запись для A
( <U0041>
) не находится между записями для a
и z
.
Все еще записи для a
и A
указывают тот же символ сортировки <a>
. Аналогично b
и B
указывают <b>
. Это переводится в веса:
Веса должны быть выражены в виде символов (в любой из форм, указанных в определении локали),
<collating-symbol>
s,<collating-element>
s, многоточия или специального символаIGNORE
. Один символ, a<collating-symbol>
, или a<collating-element>
должен представлять относительное положение в символепоследовательность сопоставленияхарактера или символа, а не самого характера или характеров. Таким образом, вместо того, чтобы присваивать весам абсолютные значения, конкретный вес выражается с использованием относительного значения порядка, присвоенного элементу сортировки на основе его порядка в характерепоследовательность сортировки.
В файле <a>
и <b>
определены в следующем порядке:
collating-symbol <a> collating-symbol <b>
Это делает соответствующую подпоследовательностьпоследовательность сортировкибыть aAbB
. Это то, что имеет значение sort
.
Чтобы подтвердить это, я (временно) переместил следующую запись порядка сортировки
<U004B> <k>;<BAS>;<CAP>;IGNORE # 649 K
в позицию непосредственно перед записью для v
, т.е. где-то между a
и z
. Я перестроил свои локали с помощью locale-gen
. Теперь sort file | tr -d '\n'
все еще возвращает …iIjJkKlLmM…
(веса не изменились, последовательность сортировки не изменилась), но grep '[a-z]' file | tr -d '\n'
выдает:
Kabcdefghijklmnopqrstuvwxyz
Это значит, что я изменил порядок сортировки, установив K
принадлежность .[a-z]
Если вы хотите grep '[a-z]' file | tr -d '\n'
вернуть перестановку aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
вместо abcdefghijklmnopqrstuvwxyz
, то вам нужно использовать локаль с другим порядком сортировки. Это может быть пользовательская локаль.