Où est passée ma ligne `uniq` ou` sort -u`, avec quelques caractères unicode

10

Que se passe-t-il dans l'extrait de code suivant? Je n'obtiens pas la sortie attendue.

Je pense que c'était un bug, mais cela arrive pour 2 programmes différents (uniq et sort), donc je soupçonne que c'est quelque chose à voir avec ... eh bien, je ne sais pas quoi ... d'où la question.

Les 3 premiers (sur 4) exemples fonctionnent, mais le 4ème échoue!.

Je m'attendrais au même comportement pour tous les personnages.
c'est à dire. pour imprimer 2 lignes (à partir des 3 lignes d'entrée) ... mais dans le 4ème cas, je n'ai qu'une ligne (pour les deux sort -uet uniq); les deux lins identiques disparaissent!

J'ai converti la sortie '\ n' en espace pour la compacité de la vue.

J'utilise uniq et je trie depuis (GNU coreutils) 7.4 ... fonctionnant sur le bureau Ubuntu 10.04.3 LTS.

Le scénario:

{
  locale -k LC_COLLATE
  echo
  for c1 in x 〼 ;do 
    for c2 in z 〇 ;do 
      echo -n "asis   : "; echo -e "$c1\n$c2\n$c2"          |tr '\n' ' ';echo
      echo -n "uniq   : "; echo -e "$c1\n$c2\n$c2" |uniq    |tr '\n' ' ';echo
      echo -n "sort -u: "; echo -e "$c1\n$c2\n$c2" |sort -u |tr '\n' ' ';echo
      echo
    done
    echo
  done
}

Le résultat:

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

asis   : x z z 
uniq   : x z 
sort -u: x z 

asis   : x 〇 〇 
uniq   : x 〇 
sort -u: 〇 x 


asis   : 〼 z z 
uniq   : 〼 z 
sort -u: 〼 z 

asis   : 〼 〇 〇 
uniq   : 〼 
sort -u: 〼 

# In the last example (of 4) where did the '〇' go? .. U+3007 IDEOGRAPHIC NUMBER ZERO
#
Peter.O
la source
Veuillez noter .. Pour que ce soit bien clair. sortseul (sans l' option -u ) ... ne gobe pas les caractères .. Ce qui entre, sort ... Cependant, comme on peut s'y attendre en expliquant Gilles des caractères unicodes "exotiques" ayant la même valeur canonique , ceux-ci les caractères ne sont pas triés, à part le fait qu'ils sont sortis en tant que groupe FIFO non trié en "haut" de la sortie du tri ... Il y a donc vraiment deux problèmes ici: 1. Les caractères ne sont pas triés comme ils le seraient "naïvement" "attendu, et 2. La caractéristique" unique "des deux sortet de uniqperdre des données (dans certains cas).
Peter.O
Mise à jour: Comme mentionné par Gilles (lorsque le tri spécifique aux paramètres régionaux n'est pas essentiel et que l'ordre des caractères est approprié), sort -uet uniqfonctionne LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u|uniq
correctement

Réponses:

11

Version courte: le classement ne fonctionne pas vraiment dans les utilitaires de ligne de commande.

Version plus longue: la fonction sous-jacente pour comparer deux chaînes est strcoll. La description n'est pas très utile, mais la méthode conceptuelle de fonctionnement consiste à convertir les deux chaînes en une forme canonique, puis à comparer les deux formes canoniques. La fonction strxfrmconstruit cette forme canonique.

Observons les formes canoniques de quelques chaînes (avec GNU libc, sous Debian squeeze):

$ export LC_ALL=en_US.UTF-8
$ perl -C255 -MPOSIX -le 'print "$_ ", unpack("h*", strxfrm($_)) foreach @ARGV' b a A à 〼 〇
b d010801020
a c010801020
A c010801090
à 101010102c6b
〼 101010102c6b102c6b102c6b
〇 101010102c6b102c6b102c6b

Comme vous pouvez le voir, 〼 et 〇 ont la même forme canonique. Je pense que c'est parce que ces caractères ne sont pas mentionnés dans les tables de classement des en_US.UTF-8paramètres régionaux. Ils sont cependant présents dans un lieu japonais.

$ export LC_ALL=ja_JP.UTF-8
$ perl -C255 -MPOSIX -le 'print "$_ ", unpack("h*", strxfrm($_)) foreach @ARGV' 〼 〇 
〼 303030
〇 3c9b

Le code source des données locales (dans Debian Squeeze) est dans /usr/share/i18n/locales/en_US, ce qui inclut /usr/share/i18n/locales/iso14651_t1_common. Ce fichier n'a pas d'entrée pour U3007ou U303C, et ils ne sont inclus dans aucune plage que je puisse trouver.

Je ne connais pas les règles pour construire l'ordre de classement , mais d'après ce que je comprends, la formulation pertinente est

Le symbole NON DÉFINI doit être interprété comme incluant toutes les valeurs de jeu de caractères codées non spécifiées explicitement ou via le symbole des points de suspension. (…) Si aucun symbole UNDEFINED n'est spécifié et que le jeu de caractères codés actuel contient des caractères non spécifiés dans cette section, l'utilitaire émet un message d'avertissement et place ces caractères à la fin de l'ordre de classement des caractères.

Il semble que Glibc ignore les caractères qui ne sont pas spécifiés. Je ne sais pas s'il y a une faille dans ma compréhension de la spécification POSIX, si j'ai raté quelque chose dans la définition des paramètres régionaux de Glibc ou s'il y a un bogue dans le compilateur de paramètres régionaux de Glibc.

Gilles 'SO- arrête d'être méchant'
la source
@ Gilles: Merci pour l'explication informative et détaillée .. Cela a du sens maintenant, mais je me demande comment utiliser "en toute sécurité" le tri .. Je ne recherche pas un tri particulièrement "sensible aux paramètres régionaux", donc tout rugueux trier ferait ... Y a-t-il une solution rapide pour cela? ... et j'obtiendrai progressivement le coup, mais cela ne se produira pas du jour au lendemain ... Par exemple, mon / usr / share / i18n / charmaps / UTF-8 contient des références aux deux personnages en question , mais être dans cette définition UTF-8 (?) ne semble pas aider ... Oh bien, à quoi ressemblerait la vie sans ses petits mystères. :) ...
Peter.O
1
@fred charmaps/UTF-8ne dit rien sur le classement, c'est ce locales/en_USqui compte. La première règle LC_COLLATEest: ne pas utiliser LC_COLLATE. Dans les paramètres régionaux C (= POSIX), le classement est raisonnable (basé strictement sur des valeurs de caractères numériques).
Gilles 'SO- arrête d'être méchant'
2
Le tri et l' aspect unique fonctionnent très bien lorsqu'ils sont précédés de LC_COLLATE=C... merci ...
Peter.O
1
Ce n'est pas que le classement ne fonctionne pas dans les utilitaires, mais que les locales de la glibc sont mal conçues. Ce comportement est (actuellement, mais voir austingroupbugs.net/view.php?id=1070 ) autorisé par POSIX, mais regrettable et indésirable.
Stéphane Chazelas
6

Pour "en toute sécurité" les sortchaînes Unicode, jetez un œil à msort:

[...] Msort offre une plus grande flexibilité dans la sélection des champs clés, plus de types de comparaison, la possibilité d'utiliser des règles de classement de différents paramètres régionaux sur différentes clés, la capacité de gérer des nombres dans des systèmes numériques non occidentaux, et une variété d'autres options manquantes en tri GNU et en tri BSD. Alors que msort comprend Unicode, le tri GNU et le tri BSD ne le font pas. [...]

http://www.billposer.org/Software/msort.html

jusqu'à
la source
@til: Merci de m'avoir informé msort. L'interface graphique en option rend l'introduction un peu plus facile pour avoir une idée de ce qui est proposé. Pouvoir copier la commande générée est très pratique ... Et oui, il trie les caractères unicode, mais (n'aimez-vous pas simplement ces "mais":) ... mais il n'a pas d' option unique : (... comme mentionné sur le lien que vous avez publié: Capabilities of GNU sort and BSD sort lacking in msort are the ability to merge files without sorting them (the --merge option) and the ability to emit only the first of an equal run (the --unique option)... Le tri fonctionne
quand