¿Dónde se ha ido mi línea `uniq` o` sort -u`, con algunos caracteres unicode

10

¿Qué está pasando en el siguiente fragmento de código? No estoy obteniendo mi salida esperada.

Creo que fue un error, pero ocurre para 2 programas diferentes (uniq y sort), por lo que sospecho que tiene algo que ver con ... bueno, no sé qué ... de ahí la pregunta.

Los primeros 3 (de 4) ejemplos funcionan, pero el cuarto falla.

Esperaría el mismo comportamiento para todos y cada uno de los personajes.
es decir. para imprimir 2 líneas (de las 3 líneas de entrada) ... pero en el cuarto caso, solo obtengo 1 línea (para ambos sort -uy uniq); ¡Los dos lins idénticos se desvanecen!

He convertido la salida '\ n' en espacio para una vista compacta.

Estoy usando uniq y ordenar desde (GNU coreutils) 7.4 ... ejecutándose en el escritorio Ubuntu 10.04.3 LTS.

La secuencia de comandos:

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

La salida:

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
fuente
Tenga en cuenta .. Para que quede bastante claro. sortsolo (sin la opción -u ) ... no engulle caracteres ... Lo que entra, sale ... Sin embargo, como puede esperarse de Gilles, la explicación de los caracteres unicode "exóticos" que tienen el mismo valor canónico , estos los caracteres no se ordenan, aparte de eso, se muestran como un grupo FIFO sin clasificar en la "parte superior" de la salida de la clasificación ... Entonces, realmente hay dos problemas aquí: 1. Los caracteres no se ordenan como podría ser "ingenuamente "esperado, y 2. La característica" única "de ambos sorty uniqperder datos (en algunos casos).
Peter.O
Actualización: como mencionó Gilles (cuando la clasificación específica de la localidad no es esencial, y el orden de los caracteres es adecuado), sort -uy uniqfunciona bien con: LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u(o |uniq)
Peter

Respuestas:

11

Versión corta: la recopilación no funciona realmente en las utilidades de línea de comandos.

Versión más larga: la función subyacente para comparar dos cadenas es strcoll. La descripción no es muy útil, pero el método conceptual de operación es convertir ambas cadenas a una forma canónica y luego comparar las dos formas canónicas. La función strxfrmconstruye esta forma canónica.

Observemos las formas canónicas de algunas cadenas (con GNU libc, bajo compresión de Debian):

$ 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 puede ver, 〼 y 〇 tienen la misma forma canónica. Creo que es porque estos caracteres no se mencionan en las tablas de clasificación de la en_US.UTF-8configuración regional. Sin embargo, están presentes en una localidad japonesa.

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

El código fuente de los datos locales (en Debian squeeze) está en /usr/share/i18n/locales/en_US, que incluye /usr/share/i18n/locales/iso14651_t1_common. Este archivo no tiene una entrada para U3007o U303C, ni están incluidos en ningún rango que pueda encontrar.

No estoy familiarizado con las reglas para construir el orden de clasificación , pero por lo que entiendo, la redacción relevante es

El símbolo INDEFINIDO se interpretará como que incluye todos los valores de juego de caracteres codificados no especificados explícitamente o mediante el símbolo de puntos suspensivos. (...) Si no se especifica un símbolo INDEFINIDO, y el juego de caracteres codificado actual contiene caracteres no especificados en esta sección, la utilidad emitirá un mensaje de advertencia y colocará dichos caracteres al final del orden de clasificación de caracteres.

Parece que Glibc ignora los caracteres que no se especifican. No sé si hay una falla en mi comprensión de la especificación POSIX, si me perdí algo en la definición de la configuración regional de Glibc o si hay un error en el compilador de la configuración regional de Glibc.

Gilles 'SO- deja de ser malvado'
fuente
@Gilles: Gracias por la explicación informativa y detallada ... Ahora tiene algo de sentido, pero me pregunto cómo usar el tipo "con seguridad" ... No busco un tipo particularmente "sensible a la localización", así que cualquier tipo haría ... ¿Hay una solución rápida para esto? ... y gradualmente voy a acostumbrarme a esto, pero no sucederá 'de la noche a la mañana ... por ejemplo, mi / usr / share / i18n / charmaps / UTF-8 contiene referencias a ambos personajes en cuestión , pero estar en esta definición UTF-8 (?) no parece ayudar ... Oh, bueno, ¿cómo sería la vida sin sus pequeños misterios? :) ...
Peter.O
1
@fred charmaps/UTF-8no dice nada sobre la colación, es lo locales/en_USque importa. La primera regla de LC_COLLATEes: no usar LC_COLLATE. En la configuración regional C (= POSIX), la clasificación es razonable (basada estrictamente en valores de caracteres numéricos).
Gilles 'SO- deja de ser malvado'
2
Las clasificadoras y único trabajo fino de aspecto cuando precedido por LC_COLLATE=C... gracias ...
Peter.O
1
No es que la recopilación no funcione en las utilidades, sino que las configuraciones regionales de glibc están mal diseñadas. Ese comportamiento es (actualmente, pero vea austingroupbugs.net/view.php?id=1070 ) permitido por POSIX, pero desafortunado e indeseable.
Stéphane Chazelas
6

Para "con seguridad" sortcadenas Unicode, tal vez eche un vistazo a msort:

[...] Msort proporciona una mayor flexibilidad en la selección de campos clave, más tipos de comparación, la capacidad de utilizar reglas de intercalación de diferentes configuraciones regionales en diferentes claves, la capacidad de manejar números en sistemas de números no occidentales y una variedad de otras opciones que faltan en GNU y BSD. Mientras que msort entiende Unicode, GNU y BSD no. [...]

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

hasta
fuente
@til: Gracias por informarmemsort . La GUI opcional hace que la introducción sea un poco más fácil para tener una idea de lo que se ofrece. Ser capaz de copiar el comando generado es muy útil ... Y sí, ordena los caracteres unicode, pero (¿no te encantan esos "peros":) ... pero no tiene una opción única : (... como se menciona en el enlace que publicaste: 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)... Aunque el tipo funciona :)
Peter.O