Порядок сортировки через LC_COLLATE
определяет не только порядок сортировки отдельных символов, но и значение диапазонов символов. Или это? Рассмотрим следующий фрагмент:
unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'
Интуитивно, B
не в [a-z]
, так что это не должно ничего выводить. Вот что происходит в Ubuntu 8.04 или 10.04. Но на некоторых машинах, на которых запущен Debian lenny или squeeze, B
встречается, потому что диапазон a-z
включает в себя все, что находится между a
и z
в порядке сортировки, включая заглавные буквы до B
конца Z
.
Все протестированные системы имеют en_US
сгенерированную локаль. Я также пытался варьировать локаль: на машинах, где B
указано выше, то же самое происходит в каждой доступной локали (в основном на латинице:, {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}
также китайские локали), кроме японской (в любой доступной кодировке) и C
/ POSIX
.
Что означают диапазоны символов в регулярных выражениях , когда вы выходите за рамки ASCII? Почему существует разница между некоторыми установками Debian с одной стороны и другими установками Debian и Ubuntu с другой? Как ведут себя другие системы? Кто прав, и кому следует сообщать об ошибке?
(Обратите внимание, что я специально спрашиваю о поведении диапазонов символов, например [a-z]
в en_US
локалях, в первую очередь в системах на основе GNU libc. Я не спрашиваю, как сопоставлять строчные или строчные буквы ASCII.)
На двух машинах Debian, один из которых B
находится в [a-z]
и один , где он не, выход LC_COLLATE=en_US locale -k LC_COLLATE
IS
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"
а выходной сигнал LC_COLLATE=en_US.utf8 locale -k LC_COLLATE
IS
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
источник
en_US
генерируется, хотя.C
языковой стандарт используется в качестве запасного варианта, и его порядок сопоставления - прямые байтовые значения, поэтомуB
не будет совпадать. Тест в локали, которая появляется в выходных данныхlocale -a
.Ответы:
Если вы используете что-то отличное от
C
локали, вам не следует использовать диапазоны, подобные тем, что[a-z]
они зависят от локали и не всегда дают ожидаемые результаты. Помимо проблемы с регистром, с которой вы уже столкнулись, некоторые локали обрабатывают символы с диакритическими знаками (например, á ) так же, как и базовый символ (то есть a ).Вместо этого используйте именованный класс символов:
Это всегда даст правильный результат для локали. Тем не менее, вам нужно выбрать локаль, чтобы отразить смысл как входного текста, так и теста, который вы пытаетесь применить.
Например, если вам нужно найти конкретное значение байта, используйте
C
локаль, которая всегда доступна:Если это не работает, как ожидалось, это действительно ошибка.
источник
locale -k
своего вопроса; он идентичен на двух машинах Debian, одна из которыхB
находится в диапазоне, а другая - нет. Кстати, я не root ни на одной машине (так что это не что-то особенное, что я делаю как администратор).echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'
возвращаетa
Иü
покаecho "Baü" | LC_COLLATE=C grep -o '[a-z]'
возвращает толькоa
. На мой взгляд, «нижний» не совсем то, чего хотел ОПC
локали. Я считаю, что это имеет отношение к ФП, который хотел сообщить об ошибке. Если вы не вC
локали, результаты использования диапазонов крайне непредсказуемы и поэтому никогда не могут считаться ошибкой. С другой стороны, если вам нужно найти конкретное значение байта, просто используйтеC
локаль. Моя вторичная точка зрения заключалась в том, что если вы действительно хотите искать строчные буквы в локали, используйте класс символов. Хотя ОП может и не искали этого, другие могут, если найдут этот вопрос.Диапазоны в регулярных выражениях должны соответствовать параметрам сортировки. Вот соответствующий стандарт: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (ищите «выражения диапазона»). Поэтому
echo B | LC_COLLATE=en_US grep '[a-z]'
следует выводитьB
данные с учетом разумного определения соответствующей локали. Я не могу объяснить, почему это иногда не работает для вас, но я был бы очень удивлен, если бы столкнулся с этим в не древней системе, которая должным образом установлена и настроена.источник
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]'
Ничего не печатает в Ubuntu 12.04 с помощью grep 2.10. На Centos 6.5 ничего не печатается с помощью grep 2.6.3. Работает ли в Debian 6.0.8 с grep 2.6.3.