Czy (powinien) LC_COLLATE wpływa na zakresy znaków?


27

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, Bnie 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ć, Bzostanie odnaleziony, ponieważ zakres a-zobejmuje wszystko, co znajduje się pomiędzy ai zw kolejności sortowania, włącznie z literami Bdzięki Z.

Wszystkie testowane systemy mają en_USwygenerowane ustawienia narodowe. Próbowałem także zmieniać ustawienia regionalne: na maszynach, które Bsą 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_USlokalizacjach, 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 Bjest, [a-z]a drugi tam, gdzie go nie ma, wynikiem LC_COLLATE=en_US locale -k LC_COLLATEjest

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_COLLATEjest

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"

1
Nie powiela się na instancji Debiana Lenny'ego, którą miałem pod ręką. Nie sprawdził jednak, czy en_USjest generowany.
alex

1
@alex Jeśli ustawienia narodowe nie są generowane, Custawienia narodowe są używane jako rezerwowe, a ich kolejność sortowania to wartości w bajtach prostych, więc Bnie zostaną dopasowane. Przetestuj w ustawieniach regionalnych wyświetlanych na wyjściu locale -a.
Gilles 'SO - przestań być zły'

1
Zauważ, że en_US NIE jest tym samym, co en_US.utf8 i zwykle oznacza en_US.iso-8859-1, w zależności od tego, co dokładnie zainstalowałeś. Jeśli en_US (bez przyrostka) nie pojawia się w danych wyjściowych ustawień narodowych -a, tak naprawdę nie masz takich ustawień narodowych. Co pokazuje LC_COLLATE = ustawienia regionalne en_US -k LC_COLLATE?
Neil Mayhew

1
Odtąd pojawiło się tutaj pytanie praktyczne, a nie teoretyczne: Dlaczego duże litery są zawarte w szeregu małych liter w wyrażeniu regularnym awk?
Caleb

1
@isaac Niestety, 7 lat później nie mam dostępu do żadnego problematycznego systemu. Wszystkie zostały zaktualizowane lub wycofane z eksploatacji.
Gilles „SO- przestań być zły”

Odpowiedzi:


3

Jeśli używasz czegoś innego niż Custawienia 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:

echo B | grep '[[:lower:]]'

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 Custawień regionalnych, które są zawsze dostępne:

echo B | LANG=C grep '[a-z]'

Jeśli to nie działa zgodnie z oczekiwaniami, to naprawdę jest to błąd.


Wiem, że nie o to prosiłem. Pytam konkretnie, co oznacza jawny zakres i dlaczego różne dystrybucje (nawet z GNU libc i GNU grep) mają różne zachowania. (Głosowane, ponieważ chociaż to, co mówisz, jest poprawne, nie ma znaczenia.)
Gilles „SO- przestań być zły”

1
Chodzi mi o to, że znaczenie wyraźnego zakresu zależy od ustawień regionalnych, a różne systemy nie muszą definiować swoich ustawień narodowych w ten sam sposób, więc nie jest to błąd. Technicznie, nadużywasz systemu, więc nie powinieneś być zaskoczony zachowaniem się „niezdefiniowanym”. Ponadto kilka osób skomentowało, że nie mogą odtworzyć zachowania w swoich systemach Debian, więc wydaje się, że w twoim systemie jest coś niezwykłego.
Neil Mayhew

1
Wiem, że zachowanie zakresów zależy od ustawień regionalnych. Pytam, jak i zdziwiłem się, że różne systemy korzystające z Glibc (i, jak się okazuje, nawet różne instalacje tej samej wersji Debiana) zachowują się inaczej. Dodałem wynik locale -kdo mojego pytania; jest identyczny na dwóch maszynach Debiana, jednej, która Bjest w zasięgu, a drugiej tam, gdzie jej nie ma. BTW: Nie jestem rootem na żadnym komputerze (więc nie robię tego jako administrator).
Gilles „SO- przestań być zły”

echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'zwraca aORAZ üpodczas gdy echo "Baü" | LC_COLLATE=C grep -o '[a-z]'zwraca tylko a. Moim zdaniem „niższy” nie jest tak naprawdę tym, czego chciał OP
Daniel Alder

Mój pierwotny punkt nadal jednak się utrzymuje: nie używaj zakresów, chyba że jesteś w Clokalizacji. Uważam, że jest to istotne dla PO, który chciał zgłosić błąd. Jeśli nie korzystasz z Custawień 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żyj Custawień 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.
Neil Mayhew

1

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ć Bdane 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.


1
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.
Ian D. Allen
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.