Beeinflusst (sollte) LC_COLLATE Zeichenbereiche?

27

Collation um durch LC_COLLATEdefiniert nicht nur die Sortierreihenfolge der einzelnen Zeichen, sondern auch die Bedeutung des Zeichenbereiches. Oder doch? Betrachten Sie das folgende Snippet:

unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'

Intuitiv Bist nicht in [a-z], daher sollte dies nichts ausgeben. Genau das passiert unter Ubuntu 8.04 oder 10.04. Aber auf einigen Computern, auf denen Debian Lenny oder Squeeze ausgeführt wird, Bwird gefunden, dass der Bereich a-zalles zwischen aund zin der Sortierreihenfolge enthält, einschließlich der Großbuchstaben Bbis Z.

Bei allen getesteten Systemen wird das en_USGebietsschema generiert. Ich habe auch versucht, das Gebietsschema zu ändern: Auf den Computern, auf denen Bdie oben angegebenen Übereinstimmungen vorliegen, geschieht dasselbe in jedem verfügbaren Gebietsschema (meistens lateinisch: {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}auch chinesisch) mit Ausnahme von Japanisch (in allen verfügbaren Codierungen) und C/ POSIX.

Was bedeuten Zeichenbereiche in regulären Ausdrücken , wenn Sie über ASCII hinausgehen? Warum gibt es einen Unterschied zwischen einigen Debian-Installationen einerseits und anderen Debian-Installationen und Ubuntu andererseits? Wie verhalten sich andere Systeme? Wer hat Recht und gegen wen sollte ein Fehler gemeldet werden?

(Beachten Sie, dass ich speziell nach dem Verhalten von Zeichenbereichen frage, z. B. [a-z]in en_USGebietsschemas, hauptsächlich auf GNU libc-basierten Systemen. Ich frage nicht, wie Kleinbuchstaben oder ASCII-Kleinbuchstaben verglichen werden sollen.)


Auf zwei Debian - Maschinen, ein , wo Bin ist [a-z]und eine , wo dies nicht der Fall, wird der Ausgang des LC_COLLATE=en_US locale -k LC_COLLATEIS

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"

und die Ausgabe von LC_COLLATE=en_US.utf8 locale -k LC_COLLATEist

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
Gilles 'SO - hör auf böse zu sein'
quelle
1
Kann nicht auf einer Debian Lenny-Instanz reproduziert werden, die ich zur Hand hatte. Es wurde jedoch nicht geprüft, ob en_USgeneriert wurde.
Alex
1
@alex Wenn das Gebietsschema nicht generiert wird, wird das CGebietsschema als Fallback verwendet, und seine Sortierreihenfolge besteht aus geraden Bytewerten, sodass Bkeine Übereinstimmung erzielt wird. Testen Sie in einem Gebietsschema, das in der Ausgabe von angezeigt wird locale -a.
Gilles 'SO - hör auf, böse zu sein'
1
Beachten Sie, dass en_US NICHT mit en_US.utf8 identisch ist und normalerweise en_US.iso-8859-1 bedeutet, je nachdem, was genau Sie installiert haben. Wenn en_US (ohne Suffix) nicht in der Ausgabe von locale -a erscheint, haben Sie dieses Gebietsschema tatsächlich nicht. Was zeigt LC_COLLATE = en_US locale -k LC_COLLATE?
Neil Mayhew
1
Inzwischen hat sich hier eher eine praktische als eine theoretische Frage ergeben: Warum sind Großbuchstaben in einer Reihe von Kleinbuchstaben in einer awk-Regex enthalten?
Caleb
1
@isaac Leider habe ich 7 Jahre später keinen Zugang zu einem problematischen System. Sie wurden alle aktualisiert oder außer Betrieb genommen.
Gilles 'SO- hör auf böse zu sein'

Antworten:

3

Wenn Sie etwas anderes als das CGebietsschema verwenden, sollten Sie keine Bereiche wie [a-z]diesen verwenden, da diese vom Gebietsschema abhängen und nicht immer die erwarteten Ergebnisse liefern. Neben dem bereits aufgetretenen Fallproblem behandeln einige Gebietsschemas Zeichen mit diakritischen Zeichen (z. B. á ) wie das Basiszeichen (z. B. a ).

Verwenden Sie stattdessen eine benannte Zeichenklasse:

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

Dies gibt immer das richtige Ergebnis für das Gebietsschema. Sie müssen jedoch das Gebietsschema auswählen, das die Bedeutung Ihres Eingabetexts und des Tests, den Sie anwenden möchten, widerspiegelt.

Wenn Sie beispielsweise einen bestimmten Bytewert suchen müssen, verwenden Sie das CGebietsschema, das immer verfügbar ist:

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

Wenn dies nicht wie erwartet funktioniert, ist es wirklich ein Fehler.

Neil Mayhew
quelle
Ich weiß, das habe ich nicht gefragt. Ich frage speziell, was ein expliziter Bereich bedeutet und warum unterschiedliche Distributionen (auch mit GNU libc und GNU grep) unterschiedliche Verhaltensweisen haben. (Abgestimmt, weil, obwohl das, was Sie sagen, richtig ist, es irrelevant ist.)
Gilles 'SO - hör auf, böse zu sein',
1
Mein Punkt ist, dass die Bedeutung eines expliziten Bereichs vom Gebietsschema abhängt und verschiedene Systeme ihre Gebietsschemas nicht auf die gleiche Weise definieren müssen. Dies ist also kein Fehler. Technisch gesehen missbrauchen Sie das System, sodass Sie nicht überrascht sein sollten, wenn Sie ein "undefiniertes" Verhalten feststellen. Außerdem haben einige Leute kommentiert, dass sie das Verhalten auf ihren Debian-Systemen nicht reproduzieren können, so dass an Ihren Systemen etwas Ungewöhnliches zu sein scheint.
Neil Mayhew
1
Ich weiß, dass das Verhalten von Bereichen von den Ländereinstellungen abhängt. Ich frage, wie und wundere mich, dass verschiedene Systeme, die Glibc verwenden (und, wie sich herausstellt, sogar verschiedene Installationen derselben Debian-Veröffentlichung), sich unterschiedlich verhalten. Ich habe die Ausgabe von locale -kzu meiner Frage hinzugefügt . Es ist auf zwei Debian-Maschinen identisch, eine, wo Bes im Bereich ist und eine, wo es nicht ist. Übrigens bin ich auf beiden Rechnern nicht root (es ist also nichts Besonderes, was ich als Administrator mache).
Gilles 'SO- hör auf böse zu sein'
echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'gibt aUND zurück, üwährend echo "Baü" | LC_COLLATE=C grep -o '[a-z]'nur zurückgibt a. In meinen Augen ist "niedriger" nicht wirklich das, was der OP wollte
Daniel Alder
Mein ursprünglicher Standpunkt bleibt jedoch bestehen: Verwenden Sie keine Bereiche, es sei denn, Sie befinden sich im CGebietsschema. Ich glaube, dies ist relevant für das OP, das einen Fehler melden wollte. Wenn Sie sich nicht in der CLändereinstellung befinden, sind die Ergebnisse der Verwendung von Bereichen sehr unvorhersehbar und können daher niemals als Fehler angesehen werden. Wenn Sie andererseits einen bestimmten Bytewert suchen müssen, verwenden Sie einfach das CGebietsschema. Wenn Sie in einem Gebietsschema wirklich nach Kleinbuchstaben suchen möchten, verwenden Sie eine Zeichenklasse. Auch wenn das OP nicht danach gesucht hat, könnten andere dies tun, wenn sie diese Frage finden.
Neil Mayhew
1

Bereiche in regulären Ausdrücken sollten die Sortierungseinstellung beachten. Hier ist der relevante Standard: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (suchen Sie nach "Bereichsausdrücken"). So echo B | LC_COLLATE=en_US grep '[a-z]'sollte Beine sinnvolle Definition des jeweiligen Gebietsschemas ausgegeben werden . Ich kann nicht erklären, warum dies manchmal bei Ihnen nicht funktioniert, aber ich wäre sehr überrascht, wenn ich dies auf einem nicht alten System antreffen würde, das ordnungsgemäß installiert und konfiguriert ist.

Peter Eisentraut
quelle
1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' Gibt unter Ubuntu 12.04 mit grep 2.10 nichts aus. Druckt unter Centos 6.5 mit grep 2.6.3 nichts. Funktioniert auf Debian 6.0.8 mit grep 2.6.3.
Ian D. Allen