Dov'è finita la mia linea `uniq` o` sort -u`, con alcuni caratteri unicode


10

Che cosa sta succedendo nel seguente frammento di codice? Non sto ottenendo il risultato atteso.

Penserei che fosse un bug, ma succede per 2 programmi diversi (uniq e sort), quindi ho il sospetto che abbia a che fare con ... beh, non so cosa ... da qui la domanda.

I primi 3 (di 4) esempi funzionano, ma il quarto fallisce !.

Mi aspetterei lo stesso comportamento per tutti i personaggi.
vale a dire. per stampare 2 righe (dalle 3 righe di input) ... ma nel 4 ° caso, ottengo solo 1 riga (per entrambi sort -ue uniq); i due lins identici svaniscono!

Ho convertito l'output '\ n' in spazio per la compattezza della vista.

Sto usando uniq e ordina da (GNU coreutils) 7.4 ... in esecuzione sul desktop Ubuntu 10.04.3 LTS.

Il copione:

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

L'output:

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
#

Si prega di notare .. Per renderlo abbastanza chiaro. sortda solo (senza l' opzione -u ) ... non inghiotte i caratteri .. Ciò che entra, viene fuori ... Tuttavia, come ci si può aspettare dalla spiegazione di Gilles dei caratteri "esotici" unicode con lo stesso valore canonico , questi i caratteri non vengono ordinati, a parte il fatto che vengono emessi come un gruppo FIFO non ordinato nella parte superiore dell'output dell'ordinamento ... Quindi ci sono davvero due problemi qui: 1. I caratteri non vengono ordinati come potrebbero essere "ingenui "previsto, e 2. La funzionalità" unica "di entrambi sorte uniqperdita di dati (in alcuni casi).
Peter

Aggiornamento: come menzionato da Gilles (quando l'ordinamento specifico per la locale non è essenziale e l'ordine dei caratteri è adatto), sort -ue uniqfunziona bene con: LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u(o |uniq)
Peter.O

Risposte:


11

Versione breve: le regole di confronto non funzionano davvero nelle utility della riga di comando.

Versione più lunga: la funzione sottostante per confrontare due stringhe è strcoll. La descrizione non è molto utile, ma il metodo concettuale di operazione consiste nel convertire entrambe le stringhe in una forma canonica e quindi confrontare le due forme canoniche. La funzione strxfrmcostruisce questa forma canonica.

Osserviamo le forme canoniche di alcune stringhe (con GNU libc, sotto 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

Come puoi vedere, 〼 e 〇 hanno la stessa forma canonica. Penso che sia perché questi personaggi non sono menzionati nelle tabelle di confronto delle impostazioni en_US.UTF-8locali. Sono, tuttavia, presenti in un locale giapponese.

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

Il codice sorgente per i dati delle impostazioni locali (in Debian squeeze) è /usr/share/i18n/locales/en_USincluso, che include /usr/share/i18n/locales/iso14651_t1_common. Questo file non ha una voce per U3007o U303C, né sono inclusi in alcun intervallo che posso trovare.

Non ho familiarità con le regole per costruire l'ordine di confronto , ma da quello che ho capito, il fraseggio rilevante è

Il simbolo UNDEFINED deve essere interpretato come comprendente tutti i valori del set di caratteri codificati non specificati in modo esplicito o tramite il simbolo dei puntini di sospensione. (...) Se non viene specificato alcun simbolo UNDEFINED e il set di caratteri codificato corrente contiene caratteri non specificati in questa sezione, l'utilità deve emettere un messaggio di avviso e collocare tali caratteri alla fine dell'ordine di confronto dei caratteri.

Sembra che Glibc stia invece ignorando i personaggi che non sono stati specificati. Non so se c'è un difetto nella mia comprensione delle specifiche POSIX, se ho perso qualcosa nella definizione della localizzazione di Glibc o se c'è un bug nel compilatore della localizzazione di Glibc.


@Gilles: Grazie per la spiegazione informativa e dettagliata .. Adesso ha un senso, ma mi chiedo come usare "in modo sicuro" l' ordinamento .. Non sto cercando un ordinamento particolarmente "locale sensibile", quindi qualsiasi sort farebbe ... C'è una soluzione rapida per questo? ... e a poco a poco capirò questo, ma non accadrà "dall'oggi al domani " ... es. my / usr / share / i18n / charmaps / UTF-8 contiene riferimenti a entrambi i personaggi in questione , ma trovarsi in questa definizione UTF-8 (?) non sembra aiutare ... Vabbè, come sarebbe la vita senza i suoi piccoli misteri. :) ...
Peter

1
@fred charmaps/UTF-8non dice nulla sulle regole di confronto, è locales/en_USimportante. La prima regola di LC_COLLATEè: non usare LC_COLLATE. Nella locale C (= POSIX), le regole di confronto sono ragionevoli (basate rigorosamente su valori di carattere numerici).
Gilles 'SO- smetti di essere malvagio' il

2
L' ordinamento e l' aspetto unico funzionano bene se preceduti da LC_COLLATE=C... grazie ...
Peter

1
Non è che le regole di confronto non funzionino nelle utility ma che le localizzazioni glibc siano progettate male. Tale comportamento è (attualmente, ma vedi austingroupbugs.net/view.php?id=1070 ) consentito da POSIX, ma sfortunato e indesiderabile.
Stéphane Chazelas,

6

Per sortstringhe Unicode "sicure" , forse dai un'occhiata a msort:

[...] Msort offre una maggiore flessibilità nella selezione dei campi chiave, più tipi di confronto, la possibilità di utilizzare regole di confronto da diverse lingue su chiavi diverse, la capacità di gestire i numeri in sistemi di numeri non occidentali e una varietà di altre opzioni che mancano in ordinamento GNU e ordinamento BSD. Considerando che msort comprende Unicode, l'ordinamento GNU e l'ordinamento BSD no. [...]

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


@til: Grazie per avermi informato msort. La GUI opzionale rende l'introduzione un po 'più semplice per avere un'idea di ciò che viene offerto. Essere in grado di copiare il comando generato è molto utile ... E sì, ordina i caratteri unicode, ma (non ti piacciono solo quei "ma":) ... ma non ha un'opzione unica : (... come menzionato nel link che hai pubblicato: 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)... L'ordinamento funziona però :)
Peter.O
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.