KolejnośćLC_COLLATE
sortowania przez określa nie tylko kolejność sortowania poszczególnych znaków, ale także znaczenie zakresów znaków. A może to? Rozważ następujący fragment kodu:
unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'
Intuicyjnie, B
nie ma go [a-z]
, więc nie powinno to nic generować. Tak dzieje się w Ubuntu 8.04 lub 10.04. Jednak na niektórych komputerach z systemem Debian lenny ani zgniatać, B
zostanie odnaleziony, ponieważ zakres a-z
obejmuje wszystko, co znajduje się pomiędzy a
i z
w kolejności sortowania, włącznie z literami B
dzięki Z
.
Wszystkie testowane systemy mają en_US
wygenerowane ustawienia narodowe. Próbowałem także zmieniać ustawienia regionalne: na maszynach, które B
są dopasowane powyżej, to samo dzieje się we wszystkich dostępnych ustawieniach narodowych (głównie w języku łacińskim:, {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}
także chińskie ustawienia regionalne) oprócz japońskiego (w dowolnym dostępnym kodowaniu) i C
/ POSIX
.
Co oznaczają zakresy znaków w wyrażeniach regularnych , gdy wykraczasz poza ASCII? Dlaczego istnieje różnica między niektórymi instalacjami Debiana z jednej strony, a innymi instalacjami Debiana i Ubuntu z drugiej strony? Jak zachowują się inne systemy? Kto ma rację i komu powinien zostać zgłoszony błąd?
(Należy pamiętać, że jestem specjalnie prosząc o zachowanie charakteru zakresów takich jak [a-z]
w en_US
lokalizacjach, głównie w systemach opartych na GNU libc. Nie pytam jak dopasować małe litery lub liter ASCII małe).
Na dwóch maszynach Debiana, jeden tam, gdzie B
jest, [a-z]
a drugi tam, gdzie go nie ma, wynikiem LC_COLLATE=en_US locale -k LC_COLLATE
jest
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"
a wyjściem LC_COLLATE=en_US.utf8 locale -k LC_COLLATE
jest
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
źródło
en_US
jest generowany.C
ustawienia narodowe są używane jako rezerwowe, a ich kolejność sortowania to wartości w bajtach prostych, więcB
nie zostaną dopasowane. Przetestuj w ustawieniach regionalnych wyświetlanych na wyjściulocale -a
.Odpowiedzi:
Jeśli używasz czegoś innego niż
C
ustawienia regionalne, nie powinieneś używać takich zakresów,[a-z]
ponieważ są one zależne od ustawień regionalnych i nie zawsze dają oczekiwane wyniki. Oprócz napotkanego już problemu, niektóre lokalizacje traktują znaki ze znakami diakrytycznymi (np. Á ) tak samo, jak znak podstawowy (tj. A ).Zamiast tego użyj nazwanej klasy znaków:
To zawsze daje poprawny wynik dla ustawień regionalnych. Musisz jednak wybrać ustawienia regionalne, aby odzwierciedlić znaczenie zarówno tekstu wejściowego, jak i testu, który próbujesz zastosować.
Na przykład, jeśli chcesz znaleźć określoną wartość bajtu, użyj
C
ustawień regionalnych, które są zawsze dostępne:Jeśli to nie działa zgodnie z oczekiwaniami, to naprawdę jest to błąd.
źródło
locale -k
do mojego pytania; jest identyczny na dwóch maszynach Debiana, jednej, któraB
jest w zasięgu, a drugiej tam, gdzie jej nie ma. BTW: Nie jestem rootem na żadnym komputerze (więc nie robię tego jako administrator).echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'
zwracaa
ORAZü
podczas gdyecho "Baü" | LC_COLLATE=C grep -o '[a-z]'
zwraca tylkoa
. Moim zdaniem „niższy” nie jest tak naprawdę tym, czego chciał OPC
lokalizacji. Uważam, że jest to istotne dla PO, który chciał zgłosić błąd. Jeśli nie korzystasz zC
ustawień regionalnych, wyniki używania zakresów są wysoce nieprzewidywalne i dlatego nigdy nie mogą być uznane za błąd. Z drugiej strony, jeśli chcesz znaleźć określoną wartość bajtu, po prostu użyjC
ustawień regionalnych. Moja druga uwaga była taka, że jeśli naprawdę chcesz szukać małych liter w ustawieniach regionalnych, użyj klasy znaków. Choć PO może tego nie szukał, inni mogliby znaleźć to pytanie.Zakresy wyrażeń regularnych powinny być zgodne z ustawieniem sortowania. Oto odpowiedni standard: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (poszukaj „wyrażeń zakresowych”).
echo B | LC_COLLATE=en_US grep '[a-z]'
Powinien więc generowaćB
dane wyjściowe, biorąc pod uwagę rozsądną definicję odpowiednich ustawień regionalnych. Nie potrafię wyjaśnić, dlaczego czasem to nie działa, ale byłbym bardzo zaskoczony, gdybym spotkał się z tym w nie-starożytnym systemie, który jest poprawnie zainstalowany i skonfigurowany.źródło
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]'
Nie drukuje niczego na Ubuntu 12.04 z grep 2.10. Nie drukuje niczego na Centos 6.5 z grep 2.6.3. Działa na Debianie 6.0.8 z grep 2.6.3.