Onde foi minha linha `uniq` ou` sort -u`, com alguns caracteres unicode

10

O que está acontecendo no seguinte snippet de código? Não estou obtendo minha saída esperada.

Eu acho que foi um bug, mas acontece em 2 programas diferentes (uniq e sort), então eu suspeito que isso tenha algo a ver com ... bem, eu não sei o que ... daí a pergunta.

Os 3 primeiros (de 4) exemplos funcionam, mas o 4º falha !.

Eu esperaria o mesmo comportamento para todos e quaisquer personagens.
ie para imprimir 2 linhas (das 3 linhas de entrada) ... mas no 4º caso, recebo apenas 1 linha (para ambos sort -ue uniq); os dois lins idênticos simplesmente desaparecem!

Eu converti a saída '\ n' para o espaço para compactar a vista.

Estou usando o uniq e classifico de (GNU coreutils) 7.4 ... executando no Ubuntu 10.04.3 LTS desktop.

O script:

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

A saída:

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
fonte
Por favor, note .. Para deixar bem claro. sortsozinho (sem a opção -u ) ... não devora caracteres. O que entra, sai ... No entanto, como pode ser esperado pela explicação de Gilles dos caracteres unicode "exóticos" que têm o mesmo valor canônico , esses Os caracteres não são classificados, exceto pelo fato de serem emitidos como um grupo FIFO não classificado para o "topo" da saída da classificação ... Portanto, existem realmente dois problemas aqui: 1. Os caracteres não são classificados como podem ser "ingenuamente "esperado e 2. O recurso" exclusivo "de ambos sorte uniqperda de dados (em alguns casos).
Peter.O
Update: Como mencionado por Gilles (quando classificações específicas a localidade não é essencial, e a ordem de caracteres é adequado), sort -ue uniqtrabalho bem com: LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u(ou |uniq)
Peter.O

Respostas:

11

Versão curta: o agrupamento realmente não funciona nos utilitários de linha de comando.

Versão mais longa: a função subjacente para comparar duas strings é strcoll. A descrição não é muito útil, mas o método conceitual de operação é converter as duas seqüências de caracteres em uma forma canônica e comparar as duas formas canônicas. A função strxfrmconstrói essa forma canônica.

Vamos observar as formas canônicas de algumas strings (com GNU libc, sob o 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

Como você pode ver, 〼 e 〇 têm a mesma forma canônica. Eu acho que é porque esses caracteres não são mencionados nas tabelas de intercalação da en_US.UTF-8localidade. No entanto, eles estão presentes em um local japonês.

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

O código fonte para os dados de localidade (no squeeze do Debian) está dentro /usr/share/i18n/locales/en_US, o que inclui /usr/share/i18n/locales/iso14651_t1_common. Este arquivo não tem uma entrada para U3007ou U303C, nem está incluído em nenhum intervalo que eu possa encontrar.

Não estou familiarizado com as regras para criar a ordem de intercalação , mas, pelo que entendi, o fraseado relevante é

O símbolo UNDEFINED deve ser interpretado como incluindo todos os valores do conjunto de caracteres codificados não especificados explicitamente ou através do símbolo de reticências. (…) Se nenhum símbolo UNDEFINED for especificado, e o atual conjunto de caracteres codificados contiver caracteres não especificados nesta seção, o utilitário emitirá uma mensagem de aviso e os colocará no final da ordem de agrupamento de caracteres.

Parece que o Glibc está ignorando caracteres que não foram especificados. Não sei se há uma falha no meu entendimento da especificação POSIX, se perdi alguma coisa na definição de localidade do Glibc ou se há um erro no compilador de localidade Glibc.

Gilles 'SO- parar de ser mau'
fonte
@Gilles: Obrigado pela explicação informativa e detalhada. Faz algum sentido agora, mas fico imaginando como usar o tipo "com segurança" . Não estou buscando um tipo particularmente "sensível ao código do idioma", portanto, qualquer problema tipo faria ... Existe uma solução rápida para isso? ... e gradualmente entendo isso, mas isso não acontecerá da noite para o dia ... por exemplo, meu / usr / share / i18n / charmaps / UTF-8 contém referências aos dois personagens em questão , mas estar nesta definição UTF-8 (?) não parece ajudar ... Oh, bem, como seria a vida sem seus pequenos mistérios. :) ...
Peter.O
1
O @fred charmaps/UTF-8não diz nada sobre agrupamento, é o locales/en_USque importa. A primeira regra de LC_COLLATEé: não use LC_COLLATE. No código do idioma C (= POSIX), o agrupamento é razoável (baseado estritamente nos valores de caracteres numéricos).
Gilles 'SO- stop be evil'
2
Os triagem e única finos trabalho aspecto quando precedido por LC_COLLATE=C... obrigado ...
Peter.O
1
Não é que o agrupamento não funcione nos utilitários, mas que os locais glibc sejam mal projetados. Esse comportamento é (atualmente, mas consulte austingroupbugs.net/view.php?id=1070 ) permitido pelo POSIX, mas é lamentável e indesejável.
Stéphane Chazelas
6

Para "com segurança" sortcadeias Unicode, talvez dê uma olhada em msort:

[...] O Msort fornece maior flexibilidade na seleção de campos-chave, mais tipos de comparação, a capacidade de usar regras de intercalação de diferentes locais em chaves diferentes, a capacidade de lidar com números em sistemas de números não-ocidentais e várias outras opções que faltam na classificação GNU e classificação BSD. Enquanto o msort entende Unicode, a classificação GNU e a classificação BSD não. [...]

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

até
fonte
@til: Obrigado por me informarmsort . A GUI opcional torna a introdução um pouco mais fácil de entender o que está em oferta. Ser capaz de copiar o comando gerado é muito útil ... E sim, ele classifica os caracteres unicode, mas (você não ama esses "buts":) ...) ... mas não tem uma opção única : (... como mencionado no link que você postou: 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)... o tipo trabalha embora :)
Peter.O