Pregunta ¿Por qué Perl moderno evita UTF-8 por defecto?


Me pregunto por qué la mayoría de las soluciones modernas creadas con Perl no permiten UTF-8 por defecto.

Entiendo que hay muchos problemas heredados para los scripts Core de Perl, donde pueden romperse las cosas. Pero, desde mi punto de vista, en el 21S t siglo, grandes proyectos nuevos (o proyectos con una gran perspectiva) deben hacer que su software UTF-8 sea a prueba desde cero. Aún así no veo que esto suceda. Por ejemplo, Alce permite estrictos y advertencias, pero no Unicode. Moderno :: Perl también reduce la repetición, pero no la manipulación UTF-8.

¿Por qué? ¿Hay alguna razón para evitar UTF-8 en los proyectos modernos de Perl en el año 2011?


Al comentar @tchrist llegué demasiado tiempo, así que lo estoy agregando aquí.

Parece que no me hice claro. Déjame intentar agregar algunas cosas.

Tchrist y veo la situación de manera muy similar, pero nuestras conclusiones están completamente en extremos opuestos. Acepto, la situación con Unicode es complicada, pero esta es la razón por la que nosotros (los usuarios y codificadores de Perl) necesitamos cierta capa (o pragma) que hace que el manejo de UTF-8 sea tan fácil como lo debe ser hoy en día.

Tchrist señalado muchos aspectos para cubrir, leeré y pensaré sobre ellos por días o incluso semanas. Aún así, este no es mi punto. Tchrist intenta demostrar que no hay una sola forma de "habilitar UTF-8". No tengo tanto conocimiento para discutir con eso. Por lo tanto, me atengo a ejemplos en vivo.

Jugué con Rakudo y UTF-8 estaba allí como lo necesitaba. No tuve ningún problema, simplemente funcionó. Tal vez haya alguna limitación en algún lugar más profundo, pero al principio, todo lo que probé funcionó como esperaba.

¿No debería ser ese un objetivo en Perl 5 moderno también? Lo enfatizo más: no estoy sugiriendo UTF-8 como el conjunto de caracteres predeterminado para Core Perl, sugiero la posibilidad de activarlo con un chasquido para aquellos que desarrollan nuevo proyectos.

Otro ejemplo, pero con un tono más negativo. Los marcos deberían facilitar el desarrollo. Hace algunos años, probé frameworks web, pero simplemente los descarté porque "habilitar UTF-8" era tan oscuro. No encontré cómo y dónde conectar el soporte de Unicode. Me llevó tanto tiempo que me resultó más fácil seguir el camino anterior. Ahora vi que había una recompensa para lidiar con el mismo problema con Masón 2: ¿Cómo limpiar Mason2 UTF-8?. Entonces, es un marco bastante nuevo, pero usarlo con UTF-8 necesita un conocimiento profundo de sus aspectos internos. Es como un gran cartel rojo: ¡ALTO, no me utilices!

Realmente me gusta Perl. Pero lidiar con Unicode es doloroso. Todavía me encuentro corriendo contra las paredes. De alguna manera Tchrist es correcto y responde mis preguntas: los nuevos proyectos no atraen a UTF-8 porque es demasiado complicado en Perl 5.


527
2018-05-28 15:12


origen


Respuestas:



𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊


𝓔𝓭𝓲𝓽: 𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨

  1. Establecer su PERL_UNICODE envariable a AS. Esto hace que todos los scripts de Perl se decodifiquen @ARGV como cadenas UTF-8, y establece la codificación de los tres de stdin, stdout y stderr en UTF-8. Ambos son efectos globales, no léxicos.

  2. En la parte superior de tu archivo fuente (programa, módulo, biblioteca, dohickey), afirma de manera prominente que estás ejecutando la versión 5.12 de Perl o mejor a través de:

    use v5.12; # minimal for unicode string feature

    use v5.14; # optimal for unicode string feature

  3. Habilite advertencias, ya que la declaración anterior solo habilita restricciones y características, no advertencias. También sugiero que se promocionen las advertencias Unicode en excepciones, así que use ambas líneas, no solo una de ellas. Sin embargo, tenga en cuenta que en v5.14, la utf8 la clase de advertencia comprende otras tres advertencias secundarias que pueden habilitarse por separado: nonchar, surrogatey non_unicode. Es posible que desee ejercer un mayor control sobre.

    use warnings;

    use warnings qw( FATAL utf8 );

  4. Declare que esta unidad fuente está codificada como UTF-8. Aunque alguna vez este pragma hizo otras cosas, ahora sirve solo a este único propósito singular y no a otro:

    use utf8;

  5. Declare que cualquier cosa que abra un archivo maneja dentro de este alcance léxico pero no en otro lado es suponer que ese flujo está codificado en UTF-8 a menos que usted le indique lo contrario. De esa forma no afectará el código de otro módulo u otro programa.

    use open qw( :encoding(UTF-8) :std );

  6. Habilitar personajes con nombre a través \N{CHARNAME}.

    use charnames qw( :full :short );

  7. Si tienes un DATA manejar, debe establecer explícitamente su codificación. Si quieres que sea UTF-8, di:

    binmode(DATA, ":encoding(UTF-8)");

Por supuesto, hay un sinfín de otros asuntos con los que eventualmente podría estar preocupado, pero estos serán suficientes para aproximarse al objetivo estatal de "hacer que todo funcione solo con UTF-8", aunque por un sentido algo debilitado de esos términos.

Otro pragma, aunque no está relacionado con Unicode, es:

      use autodie;

Es muy recomendable


 𝕹 𝖔 𝖔 𝖔 𝕸 𝖙 𝖙 𝖙 𝖙


Diciendo que "Perl debería [¡de algun modo!] habilitar Unicode de forma predeterminada "ni siquiera comienza a pensar en moverse para decir lo suficiente como para ser incluso marginalmente útil en algún tipo de caso aislado y raro". Unicode es mucho más que un repertorio de personajes más grande; también es la forma en que todos los personajes interactúan de muchas maneras.

Incluso las simples medidas mínimas que (algunas) personas parecen creer que quieren están garantizadas para romper miserablemente millones de líneas de código, código que no tiene ninguna posibilidad de "actualizarse" a su nuevo y elegante Nuevo mundo valiente modernidad.

Es mucho más complicado de lo que la gente pretende. He pensado mucho sobre esto en los últimos años. Me encantaría que me mostraran que estoy equivocado. Pero no creo que lo sea Unicode es fundamentalmente más complejo que el modelo que le gustaría imponer, y aquí hay una complejidad que nunca se puede barrer debajo de la alfombra. Si lo intentas, romperás tu propio código o el de otra persona. En algún momento, simplemente tiene que analizar y aprender de qué se trata Unicode. No puedes pretender que es algo que no es.

  hace todo lo posible por hacer que Unicode sea más fácil, más que cualquier otra cosa que haya usado alguna vez. Si crees que esto es malo, prueba algo más por un tiempo. Luego, vuelve a: o habrás regresado a un mundo mejor, o bien, traerás conocimiento de lo mismo contigo para que podamos utilizar tus nuevos conocimientos para mejorar estas cosas.


𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕷𝖎𝖘𝖙


Como mínimo, aquí hay algunas cosas que parecen ser necesarias para "habilitar Unicode de forma predeterminada", como usted lo expresó:

  1. Todo el código fuente debe estar en UTF-8 por defecto. Puedes conseguir eso con use utf8 o export PERL5OPTS=-Mutf8.

  2. los DATA manejar debe ser UTF-8. Deberá hacer esto por paquete, como en binmode(DATA, ":encoding(UTF-8)").

  3. Los argumentos del programa para las secuencias de comandos deben entenderse como UTF-8 por defecto. export PERL_UNICODE=A, o perl -CA, o export PERL5OPTS=-CA.

  4. Los flujos de entrada, salida y error estándar deben ser UTF-8 por defecto. export PERL_UNICODE=S para todos ellos, o I, Oy / o E para algunos de ellos Esto es como perl -CS.

  5. Cualquier otro asa abierta por debe considerarse UTF-8 a menos que se indique lo contrario; export PERL_UNICODE=D o con i y o para algunos de estos; export PERL5OPTS=-CD trabajaría. Lo que hace -CSAD para todos ellos.

  6. Cubre ambas bases más todas las transmisiones que abras con export PERL5OPTS=-Mopen=:utf8,:std. Ver uniquote.

  7. No quiere perderse los errores de codificación UTF-8. Tratar export PERL5OPTS=-Mwarnings=FATAL,utf8. Y asegúrate de que tus flujos de entrada sean siempre binmoded a :encoding(UTF-8), no solo para :utf8.

  8. Los puntos de código entre 128-255 deben entenderse por los puntos de código Unicode correspondientes, no solo por los valores binarios no protegidos. use feature "unicode_strings" o export PERL5OPTS=-Mfeature=unicode_strings. Eso hará uc("\xDF") eq "SS" y "\xE9" =~ /\w/. Un simple export PERL5OPTS=-Mv5.12 o mejor también obtendrá eso.

  9. Los caracteres Unicode con nombre no están habilitados por defecto, así que agregue export PERL5OPTS=-Mcharnames=:full,:short,latin,greek o algo así. Ver uninames y tcgrep.

  10. Casi siempre necesitas acceder a las funciones de el estandar Unicode::Normalize módulo varios tipos de descomposiciones export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD, y luego siempre ejecute cosas entrantes a través de NFD y material saliente desde NFC. Aún no conozco ninguna capa de E / S que yo sepa, pero vea nfc, nfd, nfkdy nfkc.

  11. Comparaciones de cadenas en el uso eq, ne, lc, cmp, sort, & c & cc siempre están equivocados. Entonces, en lugar de @a = sort @b, necesitas @a = Unicode::Collate->new->sort(@b). También podría agregar eso a su export PERL5OPTS=-MUnicode::Collate. Puede almacenar en caché la clave para las comparaciones binarias.

  12.  built-ins como printf y write hacer lo incorrecto con los datos Unicode. Tienes que usar el Unicode::GCString módulo para el primero, y ambos eso y también el Unicode::LineBreak módulo también para este último. Ver uwc y unifmt.

  13. Si quieres que cuenten como enteros, entonces tendrás que ejecutar tu \d+ capturas a través de el Unicode::UCD::num función porque está incorporado atoi(3) actualmente no es lo suficientemente inteligente.

  14. Tendrás problemas con el sistema de archivos en los sistemas de archivos. Algunos sistemas de archivos hacen cumplir silenciosamente una conversión a NFC; otros hacen cumplir silenciosamente una conversión a NFD. Y otros hacen algo más todavía. Algunos incluso ignoran el asunto por completo, lo que conduce a problemas aún mayores. Entonces debe hacer su propio manejo de NFC / NFD para mantenerse sano.

  15. Todo su código involucrando a-z o A-Z y tal DEBE SER CAMBIADO, incluyendo m//, s///y tr///. Debe destacarse como una bandera roja gritando que tu código está roto. Pero no está claro cómo debe cambiar. Obtener las propiedades correctas y comprender sus pliegues de cajas es más difícil de lo que piensas. yo suelo unichars y uniprops Todos los días.

  16. Código que usa \p{Lu} es casi tan erróneo como el código que usa [A-Za-z]. Tienes que usar \p{Upper} en cambio, y saber la razón por la cual. Sí, \p{Lowercase} y \p{Lower} son diferentes de \p{Ll} y \p{Lowercase_Letter}.

  17. Código que usa [a-zA-Z] es aún peor Y no puede usar \pL o \p{Letter}; necesita usar \p{Alphabetic}. No todos los alfabetos son letras, ¿sabes?

  18. Si buscas variables con /[\$\@\%]\w+/, entonces tienes un problema. Necesitas buscar /[\$\@\%]\p{IDS}\p{IDC}*/, e incluso eso no está pensando en las variables de puntuación o las variables del paquete.

  19. Si está buscando espacios en blanco, entonces debe elegir entre \h y \vdependiendo Y nunca deberías usar \s, Desde que NO QUIERE DECIR  [\h\v], contrario a la creencia popular.

  20. Si estás usando \n para un límite de línea, o incluso \r\n, entonces lo estás haciendo mal. Tienes que usar \R¡que no es lo mismo!

  21. Si no sabe cuándo y cómo llamar Unicode :: Stringprep, entonces será mejor que aprendas.

  22. Las comparaciones insensibles a las mayúsculas y minúsculas deben verificar si dos cosas son las mismas letras, independientemente de sus signos diacríticos y demás. La forma más fácil de hacerlo es con el estándar Unicode :: Intercalar módulo. Unicode::Collate->new(level => 1)->cmp($a, $b). También hay eq métodos y demás, y probablemente deberías aprender sobre match y substr métodos, también. Estos tienen claras ventajas sobre los integrados.

  23. A veces eso no es suficiente, y necesitas el Unicode :: Collate :: Locale módulo en su lugar, como en Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b) en lugar. Considere eso Unicode::Collate::->new(level => 1)->eq("d", "ð") es cierto, pero Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð") Es falso. Del mismo modo, "ae" y "æ" son eq si no usa las configuraciones regionales, o si usa la configuración en inglés, pero son diferentes en la configuración islandesa. ¿Ahora que? Es difícil, te digo. Puedes jugar con ucsort para probar algunas de estas cosas.

  24. Considere cómo hacer coincidir el patrón CVCV (consónico, vocal, consonante, vocal) en la cadena "niño". Su forma NFD, que habrías condenado mucho mejor a haber recordado ponerla, se convierte en "nin \ x {303} o". ¿Ahora que vas a hacer? Incluso pretendiendo que una vocal es [aeiou] (lo que está mal, por cierto), no podrás hacer algo como (?=[aeiou])\X) tampoco, porque incluso en NFD un punto de código como 'ø' no se descompone! Sin embargo, se pondrá a prueba igual a una 'o' usando la comparación UCA que acabo de mostrarle. No puede confiar en NFD, debe confiar en UCA.


𝔸 𝕤 𝕤 𝕤 𝕤 𝕤 𝕤 𝕤 𝕤 𝕤


Y eso no es todo. Hay millones de suposiciones rotas que las personas hacen sobre Unicode. Hasta que entiendan estas cosas, su código se romperá.

  1. Código que supone que puede abrir un archivo de texto sin especificar que la codificación está rota.

  2. El código que asume que la codificación predeterminada es algún tipo de codificación de plataforma nativa está roto.

  3. El código que asume que las páginas web en japonés o chino ocupan menos espacio en UTF-16 que en UTF-8 es incorrecto.

  4. El código que asume que Perl usa internamente UTF-8 es incorrecto.

  5. El código que asume que los errores de codificación siempre generarán una excepción es incorrecto.

  6. El código que asume que los puntos de código de Perl están limitados a 0x10_FFFF es incorrecto.

  7. Código que supone que puede establecer $/ algo que funcionará con cualquier separador de línea válido es incorrecto.

  8. Código que asume la igualdad de ida y vuelta en plegado de hojas, como lc(uc($s)) eq $s o uc(lc($s)) eq $s, está completamente roto y mal. Considera que el uc("σ") y uc("ς")  son ambos "Σ", pero lc("Σ") no puede devolver ambos.

  9. El código que asume que cada punto de código en minúscula tiene una mayúscula distinta, o viceversa, está roto. Por ejemplo, "ª" es una letra minúscula sin mayúscula; mientras que ambos "ᵃ" y "ᴬ" son letras, pero no son letras minúsculas; sin embargo, ambos son puntos de código en minúsculas sin las correspondientes versiones en mayúsculas. ¿Lo tengo? Son no  \p{Lowercase_Letter}, a pesar de ser ambos \p{Letter} y \p{Lowercase}.

  10. El código que supone que cambiar el caso no cambia la longitud de la cadena está roto.

  11. El código que asume que solo hay dos casos está roto. También hay título.

  12. El código que asume solo letras tiene caso roto. Más allá de las letras, resulta que los números, símbolos e incluso las marcas tienen mayúsculas y minúsculas. De hecho, cambiar el caso puede incluso hacer que algo cambie su principal categoría general, como un \p{Mark} convirtiéndose en un \p{Letter}. También puede hacer que cambie de un script a otro.

  13. El código que supone que el caso nunca depende de la configuración regional está roto.

  14. El código que supone que Unicode da una idea sobre las configuraciones regionales POSIX está roto.

  15. El código que supone que puede eliminar los signos diacríticos para obtener las letras ASCII en la base es malo, está quieto, roto, tiene daño cerebral, es incorrecto y justifica la pena capital.

  16. Código que asume que signos diacríticos \p{Diacritic} y marcas \p{Mark} son lo mismo se rompe.

  17. Código que asume \p{GC=Dash_Punctuation} cubre tanto como \p{Dash} está roto.

  18. El código que asume que el guion, los guiones y los puntos negativos son lo mismo que los demás, o que solo hay uno de cada uno, está roto e incorrecto.

  19. Código que supone que cada punto de código no ocupa más de una columna impresa.

  20. Código que asume que todo \p{Mark} los personajes ocupan cero columnas impresas está roto.

  21. Código que asume que los personajes se parecen son por igual está roto.

  22. Código que asume que los personajes que hacen no se parecen son no por igual está roto.

  23. Código que supone que hay un límite en la cantidad de puntos de código en una fila que solo uno \X puede coincidir es incorrecto

  24. Código que asume \X nunca puede comenzar con un \p{Mark} personaje es incorrecto

  25. Código que asume que \X nunca puede contener dos no-\p{Mark} personajes está mal.

  26. Código que asume que no puede usar "\x{FFFF}" Está Mal.

  27. El código que supone que un punto de código no BMP que requiere dos unidades de código UTF-16 (sustituto) codificará dos caracteres UTF-8 separados, uno por unidad de código, es incorrecto. No: codifica para un solo punto de código.

  28. El código que transcodifica de UTF-16 o UTF-32 con listas de materiales principales a UTF-8 se rompe si coloca una lista de materiales al comienzo del UTF-8 resultante. Esto es tan estúpido que al ingeniero se le deben quitar los párpados.

  29. El código que asume que el CESU-8 es una codificación UTF válida es incorrecto. Del mismo modo, el código que piensa que codifica U + 0000 como "\xC0\x80" UTF-8 está roto e incorrecto Estos muchachos también merecen el tratamiento del párpado.

  30. Código que asume caracteres como > siempre apunta hacia la derecha y < siempre apunta a la izquierda está mal, porque de hecho no lo hacen.

  31. Código que asume si primero se genera un caracter X y luego personaje Y, que esos aparecerán como XY Está Mal. A veces no lo hacen.

  32. El código que asume que ASCII es lo suficientemente bueno para escribir correctamente en inglés es estúpido, miope, analfabeto, malvado e incorrecto.  ¡Afuera con sus cabezas! Si eso parece demasiado extremo, podemos poner en peligro: de ahora en adelante solo pueden escribir con el dedo gordo de un pie (el resto aún debe ser ducktaped).

  33. Código que asume que todo \p{Math} los puntos de código son caracteres visibles es incorrecto.

  34. Código que asume \w contiene solo letras, dígitos y guiones bajos es incorrecto.

  35. Código que asume que ^ y ~ los signos de puntuación son incorrectos

  36. Código que asume que ü tiene una diéresis está mal.

  37. Código que cree cosas como  contener cualquier letra en ellos es incorrecto.

  38. Código que cree \p{InLatin} es lo mismo que \p{Latin} está atrozmente roto.

  39. Código que cree que \p{InLatin} casi siempre es útil es casi seguro que está mal.

  40. Código que cree que dado $FIRST_LETTER como la primera letra en algún alfabeto y $LAST_LETTER como la última letra en ese mismo alfabeto, eso [${FIRST_LETTER}-${LAST_LETTER}] tiene algún significado que casi siempre está completo roto, equivocado y sin sentido.

  41. El código que cree que el nombre de alguien solo puede contener ciertos caracteres es estúpido, ofensivo e incorrecto.

  42. El código que intenta reducir Unicode a ASCII no es simplemente incorrecto, nunca se debería permitir que su perpetrador vuelva a trabajar en la programación. Período. Ni siquiera estoy seguro de que se les permita volver a ver, ya que obviamente hasta ahora no les ha hecho mucho bien.

  43. El código que cree que hay alguna forma de fingir que las codificaciones de archivos de texto no existen está roto y es peligroso. Bien podría sacar el otro ojo también.

  44. Código que convierte caracteres desconocidos en ? está roto, estúpido, muerto de cerebros, y va en contra de la recomendación estándar, que dice: NO HACER ESO! RTFM por qué no.

  45. El código que cree que puede adivinar de manera confiable la codificación de un archivo de texto sin marcar es culpable de una mezcla fatal de arrogancia e ingenuidad que solo un rayo de Zeus solucionará.

  46. Código que cree que puede usar printf anchos para rellenar y justificar que los datos Unicode estén rotos y sean incorrectos.

  47. Código que cree que una vez que haya creado correctamente un archivo con un nombre de pila, cuando ejecute ls o readdir en su directorio adjunto, realmente encontrará que el archivo con el nombre que lo creó está defectuoso, roto e incorrecto. Deja de sorprenderme con esto!

  48. El código que cree que UTF-16 es una codificación de ancho fijo es estúpido, roto e incorrecto. Revoca su licencia de programación.

  49. El código que trata los puntos de código de un plano de manera diferente a los de cualquier otro plano es ipso facto roto e incorrecto Volver a la escuela.

  50. Código que cree que cosas como /s/i solo puede coincidir "S" o "s" está roto y mal Te sorprenderias.

  51. Código que usa \PM\pM* para encontrar grupos de grafemas en lugar de usar \X está roto y mal

  52. Las personas que desean regresar al mundo ASCII deben ser alentadas de todo corazón a que lo hagan, y en honor a su gloriosa actualización, deben proporcionarse gratis con una máquina de escribir manual preeléctrica para todas sus necesidades de entrada de datos. Los mensajes que se envían deben enviarse a través de un telégrafo de at a 40 caracteres por línea y entregarse a mano por un servicio de mensajería. DETENER.


𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊


Mi propio texto repetitivo en estos días tiende a verse así:

use 5.014;

use utf8;
use strict;
use autodie;
use warnings; 
use warnings    qw< FATAL  utf8     >;
use open        qw< :std  :utf8     >;
use charnames   qw< :full >;
use feature     qw< unicode_strings >;

use File::Basename      qw< basename >;
use Carp                qw< carp croak confess cluck >;
use Encode              qw< encode decode >;
use Unicode::Normalize  qw< NFD NFC >;

END { close STDOUT }

if (grep /\P{ASCII}/ => @ARGV) { 
   @ARGV = map { decode("UTF-8", $_) } @ARGV;
}

$0 = basename($0);  # shorter messages
$| = 1;

binmode(DATA, ":utf8");

# give a full stack dump on any untrapped exceptions
local $SIG{__DIE__} = sub {
    confess "Uncaught exception: @_" unless $^S;
};

# now promote run-time warnings into stackdumped exceptions
#   *unless* we're in an try block, in which 
#   case just generate a clucking stackdump instead
local $SIG{__WARN__} = sub {
    if ($^S) { cluck   "Trapped warning: @_" } 
    else     { confess "Deadly warning: @_"  }
};

while (<>)  {
    chomp;
    $_ = NFD($_);
    ...
} continue {
    say NFC($_);
}

__END__

𝕾 𝖀 𝕸 𝕸 𝖄 𝖄 𝖄


No sé cuánto más "por defecto Unicode en" puede obtener que lo que he escrito. Bueno, sí, lo hago: deberías estar usando Unicode::Collate y Unicode::LineBreak, también. Y probablemente más.

Como ve, hay demasiadas cosas Unicode que realmente hacer tiene que preocuparse por allí para nunca existe algo así como "predeterminado a Unicode".

Lo que vas a descubrir, tal como lo hicimos en 5.8, es que simplemente es imposible imponer todas estas cosas en un código que no ha sido diseñado desde el principio para dar cuenta de ello. Tu egoísmo bien intencionado acaba de romper el mundo entero.

E incluso una vez que lo haces, todavía hay problemas críticos que requieren una gran cantidad de reflexión para hacerlo bien. No hay un interruptor que puedas voltear. Nada más que cerebro, y me refiero cerebro real, será suficiente aquí. Hay una gran cantidad de cosas que debes aprender. Modulo el retroceso a la máquina de escribir manual, simplemente no puedes esperar escabullirte en la ignorancia. Este es el siglo 21ˢᵗ, y no se puede desear a Unicode por ignorancia voluntaria.

Tienes que aprenderlo. Período. Nunca será tan fácil que "todo funcione", porque eso garantizará que muchas cosas no lo hagas trabajo, lo que invalida la suposición de que siempre puede haber una manera de "hacer que todo funcione".

Es posible que pueda obtener algunos incumplimientos razonables para unas pocas y muy limitadas operaciones, pero no sin pensar en las cosas mucho más de lo que creo que tiene.

Como solo un ejemplo, el orden canónico va a causar algunos dolores de cabeza reales. "\x{F5}"  'Õ', "o\x{303}"  'Õ', "o\x{303}\x{304}"  'Ȭ'y "o\x{304}\x{303}"  'Ō' debería coincidir 'Õ', pero ¿cómo demonios vas a hacer eso? Esto es más difícil de lo que parece, pero es algo que debe tener en cuenta.

Si hay algo que sé sobre Perl, es lo que hacen y no hacen sus bits Unicode, y esto les prometo:"ᴛʜᴇʀᴇ ɪs ɴᴏ Uɴᴏ ᴍᴀɢɪᴄ ʙᴜʟʟᴇᴛ"

No puedes simplemente cambiar algunos valores predeterminados y navegar sin problemas. Es cierto que corro con PERL_UNICODE ajustado a "SA", pero eso es todo, e incluso eso es principalmente para cosas de línea de comandos. Para el trabajo real, realizo todos los pasos descritos anteriormente, y lo hago muy, ** muy ** cuidadosamente.


   ¡Ƨdləɥ ƨᴉɥʇ ɥdoɥ puɐ'λɐp əɔᴉu ɐ ʞɔ'ʞɔnl poo⅁


1089
2018-05-28 17:09



Hay dos etapas para procesar texto Unicode. El primero es "cómo puedo ingresarlo y enviarlo sin perder información". El segundo es "cómo trato el texto de acuerdo con las convenciones del idioma local".

La publicación de tchrist cubre ambos, pero la segunda parte es de donde proviene el 99% del texto de su publicación. La mayoría de los programas ni siquiera manejan las E / S correctamente, por lo que es importante entender eso antes incluso de que comiences a preocuparte por la normalización y la intercalación.

Esta publicación tiene como objetivo resolver ese primer problema

Cuando lees datos en Perl, no importa qué codificación es. Asigna algo de memoria y esconde los bytes allí. Si usted dice print $str, simplemente transfiere esos bytes a su terminal, que probablemente esté configurado para suponer que todo lo que está escrito en él es UTF-8, y su texto aparece.

Maravilloso.

Excepto, no lo es. Si intenta tratar los datos como texto, verá que Something Bad está sucediendo. No necesitas ir más allá de length para ver que lo que Perl piensa sobre tu cadena y lo que piensas sobre tu cadena no está de acuerdo. Escribe un trazador de líneas como: perl -E 'while(<>){ chomp; say length }' y escribe 文字化け y obtienes 12 ... no la respuesta correcta, 4.

Eso es porque Perl asume que su cadena no es texto. Tienes que decirle que es texto antes de que te dé la respuesta correcta.

Eso es bastante fácil; el módulo Encode tiene las funciones para hacer eso. El punto de entrada genérico es Encode::decode (o use Encode qw(decode), por supuesto). Esa función toma un hilo del mundo exterior (lo que llamaremos "octetos", una manera elegante de decir "bytes de 8 bits"), y lo convierte en un texto que Perl entenderá. El primer argumento es un nombre de codificación de caracteres, como "UTF-8" o "ASCII" o "EUC-JP". El segundo argumento es la cadena. El valor de retorno es el escalar de Perl que contiene el texto.

(También hay Encode::decode_utf8, que asume UTF-8 para la codificación.)

Si reescribimos nuestro one-liner:

perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

Tecleamos 文字 化 け y obtenemos "4" como resultado. Éxito.

Eso, allí mismo, es la solución al 99% de los problemas de Unicode en Perl.

La clave es que cada vez que un texto entre en tu programa, debes decodificarlo. Internet no puede transmitir caracteres. Los archivos no pueden almacenar caracteres. No hay caracteres en su base de datos. Solo hay octetos, y no se pueden tratar octetos como caracteres en Perl. Debe decodificar los octetos codificados en caracteres Perl con el módulo Encode.

La otra mitad del problema es obtener datos de su programa. Eso es fácil de hacer; solo dices use Encode qw(encode), decida en qué codificación estarán sus datos (UTF-8 a terminales que entienden UTF-8, UTF-16 para archivos en Windows, etc.), y luego genere el resultado de encode($encoding, $data)en lugar de simplemente generar $data.

Esta operación convierte los caracteres de Perl, que es en lo que opera su programa, en octetos que pueden ser utilizados por el mundo exterior. Sería mucho más fácil si pudiéramos simplemente enviar caracteres a través de Internet o a nuestras terminales, pero no podemos: octetos solamente. Entonces, tenemos que convertir los caracteres a octetos, de lo contrario, los resultados no están definidos.

Para resumir: codifique todas las salidas y descodifique todas las entradas.

Ahora hablaremos sobre tres cuestiones que hacen que esto sea un poco desafiante. El primero es bibliotecas. ¿Manejan el texto correctamente? La respuesta es ... lo intentan. Si descarga una página web, LWP le devolverá su resultado como texto. Si llama al método correcto en el resultado, eso es (y eso sucede decoded_contentno content, que es solo la secuencia de octetos que obtuvo del servidor.) Los controladores de base de datos pueden ser escamosos; si usa DBD :: SQLite con solo Perl, funcionará, pero si alguna otra herramienta ha puesto el texto almacenado como una codificación distinta a UTF-8 en su base de datos ... bueno ... no se manejará correctamente hasta que escriba el código para manejarlo correctamente.

La salida de datos suele ser más fácil, pero si ve "caracteres anchos impresos", entonces sabrá que está estropeando la codificación en alguna parte. Esa advertencia significa "hey, estás tratando de filtrar personajes de Perl al mundo exterior y eso no tiene ningún sentido". Su programa parece funcionar (porque el otro extremo normalmente maneja los caracteres Perl sin procesar correctamente), pero está muy roto y podría dejar de funcionar en cualquier momento. Solucionarlo con un explícito Encode::encode!

El segundo problema es el código fuente codificado en UTF-8. A menos que diga use utf8 en la parte superior de cada archivo, Perl no asumirá que su código fuente es UTF-8. Esto significa que cada vez que dices algo así como my $var = 'ほげ', estás inyectando basura en tu programa que romperá totalmente todo horriblemente. No tiene que "usar utf8", pero si no lo hace, debe no use ningún carácter que no sea ASCII en su programa.

El tercer problema es cómo Perl maneja el pasado. Hace mucho tiempo, no existía Unicode, y Perl supuso que todo era texto o binario en latín-1. De modo que cuando los datos entran en su programa y usted comienza a tratarlos como texto, Perl trata a cada octeto como un personaje Latin-1. Por eso, cuando pedimos la longitud de "文字 化,", obtuvimos 12. Perl supuso que estábamos operando en la cadena de caracteres latinos "æååã" (que tiene 12 caracteres, algunos de los cuales no son de impresión).

Esto se denomina "actualización implícita", y es algo perfectamente razonable de hacer, pero no es lo que desea si su texto no es Latin-1. Es por eso que es crítico decodificar explícitamente la entrada: si no lo haces, Perl lo hará, y podría hacerlo mal.

Las personas se topan con problemas donde la mitad de sus datos es una cadena de caracteres adecuada, y algunos aún son binarios. Perl interpretará la parte que sigue siendo binaria como si fuera un texto en latín 1 y luego lo combinaría con los datos de caracteres correctos. Esto hará que parezca que el manejo de tus personajes rompió correctamente tu programa, pero en realidad, no lo has solucionado lo suficiente.

Aquí hay un ejemplo: usted tiene un programa que lee un archivo de texto codificado en UTF-8, inserta un Unicode PILE OF POO a cada línea, e imprimirlo. Usted lo escribe como:

while(<>){
    chomp;
    say "$_ ";
}

Y luego ejecute algunos datos codificados UTF-8, como:

perl poo.pl input-data.txt

Imprime los datos de UTF-8 con un poo al final de cada línea. Perfecto, mi programa funciona!

Pero no, solo estás haciendo concatenación binaria. Estás leyendo octetos del archivo, eliminando un \n con chomp, y luego virando en los bytes en la representación UTF-8 de la PILE OF POO personaje. Cuando revise su programa para decodificar los datos del archivo y codificar la salida, notará que obtiene basura ("ð") en lugar de la caca. Esto lo llevará a creer que la decodificación del archivo de entrada es lo incorrecto. No es.

El problema es que el poo se actualiza implícitamente como latin-1. Si tu use utf8 para hacer el texto literal en lugar de binario, ¡entonces funcionará de nuevo!

(Ese es el problema número uno que veo cuando ayudo a las personas con Unicode. Partieron bien y eso rompió su programa. Eso es lo triste de los resultados indefinidos: puede tener un programa en funcionamiento durante mucho tiempo, pero cuando comienza a repararlo, se rompe. No se preocupe, si agrega instrucciones de codificación / decodificación a su programa y se rompe, significa que tiene más trabajo por hacer. La próxima vez, cuando diseñe con Unicode en mente desde el principio, será ¡más fácil!)

Eso es todo lo que necesita saber sobre Perl y Unicode. Si le dice a Perl cuáles son sus datos, tiene la mejor compatibilidad con Unicode entre todos los lenguajes de programación populares. Sin embargo, si usted supone que mágicamente sabrá qué tipo de texto lo está alimentando, va a destruir sus datos irrevocablemente. El hecho de que su programa funcione hoy en su terminal UTF-8 no significa que funcionará mañana en un archivo codificado en UTF-16. ¡Así que hazlo seguro ahora y ahorra el dolor de cabeza de destrozar la información de tus usuarios!

La parte fácil de manejar Unicode es codificar la salida y la entrada de descodificación. La parte difícil es encontrar toda su entrada y salida, y determinar qué codificación es. Pero es por eso que tienes mucho dinero :)


92
2018-05-31 18:48



Todos estamos de acuerdo en que es un problema difícil por muchas razones, pero esa es precisamente la razón para intentar que sea más fácil para todos.

Hay un módulo reciente sobre CPAN, utf8 :: todo, que intenta "encender Unicode. Todo".

Como se ha señalado, no se puede hacer mágicamente que todo el sistema (programas externos, solicitudes web externas, etc.) también utilicen Unicode, pero podemos trabajar juntos para crear herramientas sensatas que faciliten la realización de problemas comunes. Esa es la razón por la que somos programadores.

Si utf8 :: all no hace algo que crees que debería, mejorémoslo para mejorarlo. O hagamos herramientas adicionales que, juntas, puedan satisfacer las diferentes necesidades de las personas de la mejor manera posible.

`


46
2018-05-29 18:59



Creo que malinterpretas a Unicode y su relación con Perl. No importa de qué forma almacene datos, Unicode, ISO-8859-1, u otras muchas cosas, su programa debe saber cómo interpretar los bytes que obtiene como entrada (decodificación) y cómo representar la información que desea generar (codificación). Haga la interpretación incorrecta y distorsione los datos. No hay una configuración mágica predeterminada dentro de su programa que le diga a las cosas que están fuera de su programa cómo actuar.

Crees que es difícil, muy probablemente, porque estás acostumbrado a que todo sea ASCII. Todo lo que debería haber estado pensando simplemente fue ignorado por el lenguaje de programación y todas las cosas con las que tuvo que interactuar. Si todo usara solo UTF-8 y no tuviera otra opción, entonces UTF-8 sería igual de fácil. Pero no todo usa UTF-8. Por ejemplo, no quiere que su manejador de entrada piense que está obteniendo octetos UTF-8 a menos que realmente lo esté, y no quiere que sus identificadores de salida sean UTF-8 si lo que lee de ellos puede manejar UTF-8 . Perl no tiene manera de saber esas cosas. Es por eso que eres el programador.

No creo que Unicode en Perl 5 sea demasiado complicado. Creo que da miedo y la gente lo evita. Hay una diferencia Para ese fin, puse Unicode en Learning Perl, 6ª edición, y hay muchas cosas en Unicode en Efectiva Programación Perl. Tienes que pasar el tiempo para aprender y entender Unicode y cómo funciona. De lo contrario, no podrá usarlo efectivamente.


34
2018-05-29 17:51



Mientras leo este hilo, a menudo tengo la impresión de que la gente está usando "UTF-8"como sinónimo de"Unicode". Haga una distinción entre los" Puntos de código "de Unicode, que son un pariente ampliado del código ASCII y varias" codificaciones "de Unicode. Y hay algunos de ellos, de los cuales UTF-8, UTF-16 y UTF-32 son los actuales y algunos más están obsoletos.

Por favor, UTF-8 (y todos los demás codificaciones) existe y tiene significado en la entrada o solo en la salida. Internamente, desde Perl 5.8.1, todas las cadenas se mantienen como "puntos de código" Unicode. Es cierto que debe habilitar algunas características como se cubrió con admiración anteriormente.


27
2018-05-30 09:41



Hay una cantidad realmente horrible de códigos antiguos en la naturaleza, muchos de ellos en forma de módulos comunes de CPAN. He descubierto que tengo que ser bastante cuidadoso al habilitar Unicode si uso módulos externos que puedan verse afectados por él, y todavía estoy tratando de identificar y corregir algunos fallos relacionados con Unicode en varios scripts de Perl que uso regularmente (en particular, iTiVo falla mal en cualquier cosa que no sea ASCII de 7 bits debido a problemas de transcodificación).


9
2018-05-28 15:19



Debe habilitar la característica de cadenas Unicode, y esta es la predeterminada si usa v5.14;

Realmente no deberías usar identificadores unicode esp. para código extranjero vía utf8 ya que son inseguros en perl5, solo cperl tiene ese derecho. Ver p. http://perl11.org/blog/unicode-identifiers.html

Con respecto a utf8 para sus manejos de archivo / flujos: Usted necesita decidir por su cuenta la codificación de sus datos externos. Una biblioteca no puede saber eso, y dado que ni siquiera libc admite utf8, los datos utf8 correctos son raros. Hay más wtf8, la aberración de Windows de utf8.

Por cierto: Moose no es realmente "Modern Perl", simplemente secuestraron el nombre. Moose es perfecto Perm posmoderno estilo Larry Wall mezclado con el estilo Bjarne Stroustrup, todo va, con una aberración ecléctica de la sintaxis perl6 adecuada, p. utilizando cadenas para nombres de variables, sintaxis de campos horribles y una implementación ingenua muy inmadura que es 10 veces más lenta que una implementación adecuada. cperl y perl6 son los verdaderos perls modernos, donde la forma sigue a la función y la implementación se reduce y optimiza.


1
2018-05-14 11:59