В течение прошлых нескольких месяцев я узнавал о командной строке с помощью William E. Shotts Командную строку Linux. Командная строка Linux остается популярной книгой для новичков, которые хотели бы узнать больше о командной строке Linux.
В одной из глав это представляет tr
команда. В книге говорится, что наборы символов могут быть созданы одним из трех способов: перечислимый список такой как ABCDEFGHIJKLMNOPQRSTUVWXYZ
; диапазон символов, такой как A-Z
; и классы символов POSIX, такой как [:upper:]
.
Часть, которую я не понимаю, - когда книга говорит читателю быть осторожным об использовании диапазонов символов для набора символов из-за порядка сопоставления локали и предлагает, чтобы читатель использовал классы символов POSIX вместо этого.
Я лично никогда не встречался с проблемой с помощью диапазонов символов такой как A-Z
с
echo "lowercase letters" | tr a-z A-Z
итак, почему я должен воздержаться от использования диапазонов символов в пользу классов символов POSIX?
В случае, если Вы задаетесь вопросом, моя локаль является en_US.UTF-8.
Вы используете UTF-8. Yay! ASCII и следовательно UTF-8 (потому что парни UTF пытались сделать это надмножеством ASCII), имеют алфавиты в алфавитном порядке без разрывов, таким образом, a-z
содержит все нормальные символы нижнего регистра и ничто иное, и так далее.
Однако это не должно быть верно на некотором другом кодировании. Классическим примером является EBCDIC:
Разрывы между буквами сделали простой код, который работал в сбое ASCII над EBCDIC. Например,
for (c='A';c<='Z';++c)
установил быc
к 26 буквам в алфавите ASCII, но 40 символам включая многие неназначенные в EBCDIC. Фиксация этого необходимого усложнения кода с вызовами функции, которому значительно сопротивлялись программисты.
Я хотел бы думать, что никто не использует странный материал как это еще, но кто знает?
TR GNU не поддерживает Unicode, AFAIK, но для программ, которые делают, [[:upper:]]
также соответствовал бы символам Unicode, которые считают алфавитами верхнего регистра, например, полноширинным "A", или с диакритическим знаком: À.
$ printf "%s\n" A a A À | grep '[[:upper:]]'
A
A
À
$ printf "%s\n" A a A À | grep '[A-Z]' # I'm also using Unicode, so grep tries to be friendly
A
À
$ printf "%s\n" A a A À | LC_ALL=C grep '[A-Z]'
A