perl unicode sorting collation

¿Cuál es el “orden de comparación de cadenas estándar” de Perl?



unicode sorting (2)

No puedo responder a toda la pregunta, así que permítame concentrarme en una parte:

const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);

... parece que una vez que tiene pv1 y pv2 , que fueron coaccionados a char * , ahora solo se comparan byte a byte porque están coaccionados a void * . Es eso lo que pasa con memcmp

Bastante mucho Las principales diferencias entre memcmp y strcmp son:

  1. strcmp se detendrá una vez que vea un valor NULL (es decir, ''/0'' ), y Perl permite que los escalares tengan NULL s incrustados
  2. memcmp menudo se ejecuta un poco más rápido que strcmp

Pero aparte de eso vas a obtener los mismos resultados.

Esta es realmente una pregunta doble, mis dos objetivos finales tienen respuestas a:

  • ¿Cuál es el orden de comparación de cadenas estándar, en términos de la mecánica?
  • ¿Cuál es un nombre mejor para eso para que pueda actualizar los documentos?

La documentación de Perl para sort dice que sin un bloque, la sort usa el "orden de comparación de cadena estándar". Pero ¿cuál es esa orden? Debería haber un mejor nombre para ello. Para esta pregunta, me refiero específicamente a la situación donde la locale no está vigente, ya que eso define su propio orden.

En años pasados, normalmente llamábamos el orden de clasificación estándar "ASCIIbéticamente". Está en Learning Perl y muchos otros libros. Sin embargo, ese término está fechado. Perl ha sido compatible con Unicode desde 5.6. Hablar de ASCII es de la vieja escuela. Como Perl también es consciente de Unicode, conoce las cadenas de caracteres. En sv.c , Perl_sv_cmp conoce la locale , los bytes y UTF-8. Los dos primeros son fáciles. Pero no confío en el tercero.

/* =for apidoc sv_cmp Compares the strings in two SVs. Returns -1, 0, or 1 indicating whether the string in C<sv1> is less than, equal to, or greater than the string in C<sv2>. Is UTF-8 and ''use bytes'' aware, handles get magic, and will coerce its args to strings if necessary. See also C<sv_cmp_locale>. =cut */

Cuando Perl clasifica utilizando UTF-8, ¿qué es realmente la clasificación? Los bytes a los que se codifica la cadena, los caracteres que representa (¿incluyendo marcas, quizás?), O algo más? Creo que esta es la línea relevante en sv.c (línea 6698 para commit 7844ec1):

pv1 = tpv = (char*)bytes_to_utf8((const U8*)pv1, &cur1);

Si estoy leyendo bien (usando mi C oxidada), pv1 se convierte en octetos, se convierte en UTF-8, y luego en caracteres (en el sentido de C). Creo que eso significa que se clasifica por la codificación UTF-8 (es decir, los bytes reales que utiliza UTF-8 para representar un punto de código). Otra forma de decirlo es que no se clasifica en grafemas. Creo que casi me he convencido a mí mismo de que estoy leyendo esto correctamente, pero algunos de ustedes saben mucho más sobre esto que yo.

A partir de eso, la siguiente línea interesante es 6708:

const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);

Para mí, parece que una vez que tiene pv1 y pv2 , que fueron obligados a char * , ahora solo se comparan byte a byte porque están obligados a void * . ¿Es eso lo que pasa con memcmp , que parece que solo está comparando bits según los diversos documentos que he leído hasta ahora? De nuevo, me pregunto qué me falta en el viaje desde bytes-> utf8-> char-> bytes, como quizás un paso de normalización de Unicode. Revisar Perl_bytes_to_utf8 en utf8.c no me ayudó a responder esa pregunta.

Como nota al margen, me pregunto si esto es lo mismo que el algoritmo de clasificación de Unicode . Si es así, ¿por qué existe Unicode::Collate ? Por lo que parece, no creo que el sort de Perl maneje la equivalencia canónica.


UTF-8 tiene la propiedad de que al ordenar un byte por byte de cadena UTF-8 de acuerdo con el valor de byte se obtiene el mismo orden que al ordenarlo punto de código por punto de código según el número de punto de código. Es decir, sé sin mirar que la representación UTF-8 de U + 2345 es lexicográficamente después de la representación UTF-8 de U + 1234.

En cuanto a la normalización, el núcleo de Perl no sabe nada al respecto; para obtener una clasificación y comparación precisas entre los diferentes formularios, querría ejecutar todas sus cadenas a través de Unicode::Normalize y convertirlas todas al mismo formulario de normalización. No puedo comentar cuál es el mejor para un propósito determinado, principalmente porque no tengo idea.

Además, la clasificación y el cmp se ven afectados por la locale pragma si está en uso; utiliza el orden de colación POSIX. Usar la use locale , una use locale 8 bits y unicode en conjunto es una receta para el desastre, pero use locale , una use locale UTF-8 y unicode debería funcionar de manera útil. No puedo decir que lo haya intentado. Hay una gran cantidad de información en perllocale y perlunicode todos modos.