LC_COLLATE affecte-t-il (devrait-il) affecter les plages de caractères?

27

L' ordre de LC_COLLATEclassement via définit non seulement l'ordre de tri des caractères individuels, mais également la signification des plages de caractères. Ou alors? Considérez l'extrait de code suivant:

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

Intuitivement, Bn'est pas dedans, [a-z]donc cela ne devrait rien produire. C'est ce qui se passe sur Ubuntu 8.04 ou 10.04. Mais sur certaines machines en cours d' exécution ou de Debian Squeeze, Bse trouve, parce que la gamme a-zcomprend tout ce qui est entre aet zdans l'ordre de classement, y compris les lettres majuscules Bpar Z.

Tous les systèmes testés ont en_USgénéré les paramètres régionaux. J'ai également essayé de faire varier les paramètres régionaux: sur les machines où Best comparé ci-dessus, la même chose se produit dans tous les paramètres régionaux disponibles (principalement en latin {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}:, également dans les paramètres régionaux chinois) sauf le japonais (dans n'importe quel encodage disponible) et C/ POSIX.

Que signifient les plages de caractères dans les expressions régulières , lorsque vous allez au-delà de l'ASCII? Pourquoi y a-t-il une différence entre certaines installations Debian d'une part, et d'autres installations Debian et Ubuntu d'autre part? Comment se comportent les autres systèmes? Qui a raison et contre qui un bug devrait-il être signalé?

(Notez que je pose spécifiquement des questions sur le comportement des plages de caractères telles que [a-z]dans les en_USlocales, principalement sur les systèmes basés sur la libc GNU. Je ne demande pas comment faire correspondre les lettres minuscules ou les lettres minuscules ASCII.)


Sur deux machines Debian, une où se Btrouve [a-z]et une où elle ne l'est pas, la sortie de LC_COLLATE=en_US locale -k LC_COLLATEest

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

et la sortie de LC_COLLATE=en_US.utf8 locale -k LC_COLLATEest

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
Gilles 'SO- arrête d'être méchant'
la source
1
Ne se reproduit pas sur une instance Debian Lenny que j'ai eu à portée de main. N'a pas vérifié si en_USest généré, cependant.
alex
1
@alex Si les paramètres régionaux ne sont pas générés, les Cparamètres régionaux sont utilisés comme solution de repli et leur ordre de classement est des valeurs d'octets droits, donc Bils ne seront pas mis en correspondance. Testez dans un environnement local qui apparaît dans la sortie de locale -a.
Gilles 'SO- arrête d'être méchant'
1
Notez que en_US n'est PAS identique à en_US.utf8 et signifie généralement en_US.iso-8859-1, selon exactement ce que vous avez installé. Si en_US (sans suffixe) n'apparaît pas dans la sortie de locale -a, vous n'avez pas réellement cette locale. Que montre LC_COLLATE = en_US locale -k LC_COLLATE?
Neil Mayhew
1
@isaac Malheureusement, 7 ans plus tard, je ne semble avoir accès à aucun système problématique. Ils ont tous été mis à niveau ou mis hors service.
Gilles 'SO- arrête d'être méchant'

Réponses:

3

Si vous utilisez autre chose que les Cparamètres régionaux, vous ne devez pas utiliser des plages comme [a-z]celles-ci car elles dépendent des paramètres régionaux et ne donnent pas toujours les résultats attendus. En plus du problème de cas que vous avez déjà rencontré, certains paramètres régionaux traitent les caractères avec des signes diacritiques (par exemple á ) de la même manière que le caractère de base (c'est -à- dire a ).

Utilisez plutôt une classe de caractères nommée:

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

Cela donnera toujours le résultat correct pour les paramètres régionaux. Cependant, vous devez choisir les paramètres régionaux pour refléter la signification de votre texte d'entrée et du test que vous essayez d'appliquer.

Par exemple, si vous devez trouver une valeur d'octet particulière, utilisez les Cparamètres régionaux, qui sont toujours disponibles:

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

Si cela ne fonctionne pas comme prévu, c'est vraiment un bug.

Neil Mayhew
la source
Je sais que ce n'est pas ce que j'ai demandé. Je demande spécifiquement ce que signifie une plage explicite et pourquoi différentes distributions (même avec GNU libc et GNU grep) ont des comportements différents. (Voté parce que même si ce que vous dites est correct, ce n'est pas pertinent.)
Gilles 'SO- arrête d'être méchant'
1
Mon point est que la signification d'une plage explicite dépend des paramètres régionaux, et différents systèmes ne sont pas nécessaires pour définir leurs paramètres régionaux de la même manière, ce n'est donc pas un bogue. Techniquement, vous abusez du système, vous ne devriez donc pas être surpris d'avoir un comportement "indéfini". De plus, plusieurs personnes ont commenté qu'elles ne pouvaient pas reproduire le comportement sur leurs systèmes Debian, il semble donc qu'il y ait quelque chose d'inhabituel dans vos systèmes.
Neil Mayhew
1
Je sais que le comportement des plages dépend des paramètres régionaux. Je demande comment, et surpris que différents systèmes utilisant Glibc (et, il s'avère, même différentes installations de la même version de Debian) aient des comportements différents. J'ai ajouté la sortie de locale -kà ma question; il est identique sur deux machines Debian, une où elle Best dans la plage et une où elle ne l'est pas. BTW, je ne suis root sur aucune des deux machines (donc ce n'est pas quelque chose de particulier que je fais en tant qu'administrateur).
Gilles 'SO- arrête d'être méchant'
echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'renvoie aET ütandis que echo "Baü" | LC_COLLATE=C grep -o '[a-z]'renvoie uniquement a. À mes yeux, "plus bas" n'est pas vraiment ce que le PO voulait
Daniel Alder
Mon point d'origine est toujours valable, cependant: n'utilisez pas de plages sauf si vous êtes dans les Cparamètres régionaux. Je pense que cela concerne le PO, qui cherchait à signaler un bug. Si vous n'êtes pas dans leC paramètres régionaux, les résultats de l'utilisation des plages sont très imprévisibles et ne peuvent donc jamais être considérés comme un bogue. D'un autre côté, si vous avez besoin de trouver une valeur d'octet particulière, utilisez simplement les Cparamètres régionaux. Mon point secondaire était que si vous voulez vraiment rechercher des lettres minuscules dans un environnement local, utilisez une classe de caractères. Même si le PO ne l'a peut-être pas recherché, d'autres le pourraient s'ils trouvent cette question.
Neil Mayhew le
1

Les plages dans les expressions régulières doivent respecter le paramètre de classement. Voici la norme pertinente: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (recherchez les "expressions de plage"). La echo B | LC_COLLATE=en_US grep '[a-z]'sortie devrait donc Bdonner une définition raisonnable des paramètres régionaux respectifs. Je ne peux pas expliquer pourquoi cela ne fonctionne parfois pas pour vous, mais je serais très surpris si je rencontrais cela sur un système non ancien correctement installé et configuré.

Peter Eisentraut
la source
1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' N'imprime rien sur Ubuntu 12.04 avec grep 2.10. N'imprime rien sur Centos 6.5 avec grep 2.6.3. Fonctionne sur Debian 6.0.8 avec grep 2.6.3.
Ian D. Allen