Wo ist meine Zeile "uniq" oder "sort -u" mit einigen Unicode-Zeichen geblieben?

10

Was ist im folgenden Code-Snippet los? Ich erhalte nicht meine erwartete Ausgabe.

Ich würde denken, dass es ein Fehler war, aber es passiert für 2 verschiedene Programme (uniq und sort), also vermute ich, dass es etwas damit zu tun hat ... nun, ich weiß nicht was ... daher die Frage.

Die ersten 3 (von 4) Beispiele funktionieren, aber das vierte schlägt fehl!.

Ich würde für alle Charaktere das gleiche Verhalten erwarten.
dh. 2 Zeilen ausdrucken (aus den 3 Eingabezeilen) ... aber im 4. Fall bekomme ich nur 1 Zeile (für beide sort -uund uniq); Die beiden identischen Lins verschwinden einfach!

Ich habe die Ausgabe '\ n' für eine kompakte Ansicht in Platz konvertiert.

Ich verwende Uniq und sortiere nach (GNU Coreutils) 7.4 ... und laufe auf Ubuntu 10.04.3 LTS Desktop.

Das Skript:

{
  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
}

Die Ausgabe:

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
quelle
Bitte beachten Sie .. Um es ganz klar zu machen. sortallein (ohne die Option -u ) ... verschlingt keine Zeichen. Was rein geht, kommt raus ... Wie Gilles Erklärung der "exotischen" Unicode-Zeichen mit dem gleichen kanonischen Wert erwartet , sind dies jedoch Zeichen werden nicht sortiert, außer dass sie als unsortierte FIFO-Gruppe an die "Spitze" der Sortierausgabe ausgegeben werden ... Hier gibt es also wirklich zwei Probleme: 1. Die Zeichen werden nicht so sortiert, wie es "naiv" sein könnte "erwartet und 2. Die" einzigartige "Funktion von beiden sortund uniqDatenverlust (in einigen Fällen).
Peter.O
Update: Wie von Gilles erwähnt (wenn die länderspezifische Sortierung nicht unbedingt erforderlich ist und die Zeichenreihenfolge geeignet ist) sort -uund gut uniqfunktioniert mit: LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u(oder |uniq)
Peter.O

Antworten:

11

Kurzversion: Die Sortierung funktioniert in Befehlszeilenprogrammen nicht wirklich.

Längere Version: Die zugrunde liegende Funktion zum Vergleichen von zwei Zeichenfolgen ist strcoll. Die Beschreibung ist nicht sehr hilfreich, aber die konzeptionelle Methode besteht darin, beide Zeichenfolgen in eine kanonische Form umzuwandeln und dann die beiden kanonischen Formen zu vergleichen. Die Funktion strxfrmkonstruiert diese kanonische Form.

Beobachten wir die kanonischen Formen einiger Strings (mit GNU libc unter 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

Wie Sie sehen können, haben 〼 und 〇 dieselbe kanonische Form. Ich denke, das liegt daran, dass diese Zeichen in den Sortiertabellen des en_US.UTF-8Gebietsschemas nicht erwähnt werden . Sie sind jedoch in einem japanischen Gebietsschema vorhanden.

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

Der Quellcode für die Gebietsschemadaten (in Debian Squeeze) befindet sich in /usr/share/i18n/locales/en_US, einschließlich /usr/share/i18n/locales/iso14651_t1_common. Diese Datei hat keinen Eintrag für U3007oder U303Cund ist auch nicht in einem Bereich enthalten, den ich finden kann.

Ich bin nicht mit den Regeln zum Erstellen der Sortierreihenfolge vertraut , aber nach meinem Verständnis ist die relevante Formulierung

Das Symbol UNDEFINED ist so zu interpretieren, dass es alle codierten Zeichensatzwerte enthält, die nicht explizit oder über das Auslassungssymbol angegeben wurden. (…) Wenn kein UNDEFINED-Symbol angegeben ist und der aktuell codierte Zeichensatz Zeichen enthält, die in diesem Abschnitt nicht angegeben sind, gibt das Dienstprogramm eine Warnmeldung aus und setzt diese Zeichen am Ende der Zeichensortierungsreihenfolge.

Es sieht so aus, als würde Glibc stattdessen Zeichen ignorieren, die nicht angegeben sind. Ich weiß nicht, ob mein Verständnis der POSIX-Spezifikation fehlerhaft ist, ob ich etwas in der Gebietsschemadefinition von Glibc übersehen habe oder ob ein Fehler im Glibc-Gebietsschema-Compiler vorliegt.

Gilles 'SO - hör auf böse zu sein'
quelle
@ Gilles: Danke für die informative und detaillierte Erklärung. Es macht jetzt Sinn, aber ich frage mich, wie man sort "sicher" verwendet . Ich bin nicht nach einer besonders "locale sensitive" Sortierung, also keine grobe sort würde reichen ... Gibt es eine schnelle Problemumgehung dafür? ... und ich werde nach und nach den Dreh raus bekommen, aber es wird nicht 'über Nacht' passieren ... zB .. mein / usr / share / i18n / charmaps / UTF-8 enthält Verweise auf beide fraglichen Charaktere , aber in dieser UTF-8-Definition (?) zu sein, scheint nicht zu helfen ... Na ja, wie wäre das Leben ohne seine kleinen Geheimnisse. :) ...
Peter.O
1
@fred charmaps/UTF-8sagt nichts über Kollation, es ist locales/en_USwichtig. Die erste Regel LC_COLLATElautet: Nicht verwenden LC_COLLATE. Im Gebietsschema C (= POSIX) ist die Sortierung sinnvoll (ausschließlich basierend auf numerischen Zeichenwerten).
Gilles 'SO - hör auf böse zu sein'
2
Die Sortierung und der einzigartige Aspekt funktionieren gut, wenn LC_COLLATE=C... danke ...
Peter.O
1
Es ist nicht so, dass die Sortierung in Dienstprogrammen nicht funktioniert, sondern dass glibc-Gebietsschemas schlecht gestaltet sind. Dieses Verhalten ist (derzeit, aber siehe austingroupbugs.net/view.php?id=1070 ) von POSIX zulässig, aber unglücklich und unerwünscht.
Stéphane Chazelas
6

Um sortUnicode-Zeichenfolgen "sicher" zu machen , schauen Sie sich vielleicht Folgendes an msort:

[...] Msort bietet mehr Flexibilität bei der Auswahl von Schlüsselfeldern, mehr Vergleichstypen, die Möglichkeit, Kollatierungsregeln aus verschiedenen Ländereinstellungen auf verschiedenen Schlüsseln zu verwenden, die Fähigkeit, Zahlen in nicht-westlichen Zahlensystemen zu verarbeiten, und eine Vielzahl anderer fehlender Optionen in GNU-Sortierung und BSD-Sortierung. Während msort Unicode versteht, ist dies bei GNU-Sortierung und BSD-Sortierung nicht der Fall. [...]

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

bis
quelle
@til: Danke, dass du mich darauf aufmerksam gemacht hast msort. Die optionale Benutzeroberfläche erleichtert die Einführung, um ein Gefühl für das Angebot zu bekommen. Es ist sehr praktisch, den generierten Befehl kopieren zu können ... Und ja, es sortiert die Unicode-Zeichen, aber (lieben Sie nicht nur diese "Aber" :) ... aber es gibt keine eindeutige Option: (... wie auf dem Link erwähnt, den Sie gepostet haben: 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)... Die Sortierung funktioniert jedoch :)
Peter.O