Me pregunto por qué la mayoría de las soluciones modernas creadas con Perl no habilitan UTF-8 de forma predeterminada.
Entiendo que hay muchos problemas heredados para los scripts centrales de Perl, donde pueden romper cosas. Pero, desde mi punto de vista, en el 21 st siglo, grandes proyectos nuevos (o proyectos con una perspectiva grande) deben hacer su software de prueba de UTF-8 a partir de cero. Aún así no veo que suceda. Por ejemplo, Moose habilita estrictos y advertencias, pero no Unicode . Modern :: Perl también reduce el repetitivo, pero no maneja UTF-8.
¿Por qué? ¿Hay algunas razones para evitar UTF-8 en los proyectos modernos de Perl en el año 2011?
Comentando @tchrist fue demasiado largo, así que lo agrego aquí.
Parece que no me hice claro. Déjame intentar agregar algunas cosas.
Tchrist y yo vemos la situación de manera bastante similar, pero nuestras conclusiones están completamente en extremos opuestos. Estoy de acuerdo, la situación con Unicode es complicada, pero es por eso que nosotros (usuarios y codificadores de Perl) necesitamos alguna capa (o pragma) que haga que el manejo de UTF-8 sea tan fácil como debe ser hoy en día.
Si Cristo señaló muchos aspectos a cubrir, los leeré y pensaré en ellos durante 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. Entonces, me quedo con los ejemplos en vivo.
Jugué con Rakudo y UTF-8 estaba allí cuando 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 el Perl 5 moderno también? Lo enfatizo más: no estoy sugiriendo UTF-8 como el conjunto de caracteres predeterminado para el núcleo de Perl, sugiero la posibilidad de activarlo con un chasquido para aquellos que desarrollan nuevos proyectos.
Otro ejemplo, pero con un tono más negativo. Los marcos deberían facilitar el desarrollo. Hace algunos años, probé los frameworks web, pero los descarté porque "habilitar UTF-8" era muy 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 viejo camino. Ahora vi que había una recompensa por tratar el mismo problema con Mason 2: ¿Cómo hacer que Mason2 UTF-8 esté limpio? . Por lo tanto, es un marco bastante nuevo, pero usarlo con UTF-8 necesita un conocimiento profundo de sus componentes internos. Es como un gran cartel rojo: ¡ALTO, no me uses!
Realmente me gusta Perl. Pero lidiar con Unicode es doloroso. Todavía me encuentro corriendo contra las paredes. De alguna manera, tchrist tiene razón y responde mis preguntas: los nuevos proyectos no atraen a UTF-8 porque es demasiado complicado en Perl 5.
Respuestas:
𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 ℞ : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨
Establezca su
PERL_UNICODE
envariable aAS
. Esto hace que todos los scripts de Perl se decodifiquen@ARGV
como cadenas UTF ‑ 8 y establece la codificación de los tres stdin, stdout y stderr en UTF ‑ 8. Ambos son efectos globales, no léxicos.En la parte superior de su archivo fuente (programa, módulo, biblioteca,
do
chupetón), afirme de manera destacada que está ejecutando perl versión 5.12 o superior a través de:Habilite las advertencias, ya que la declaración anterior solo habilita restricciones y características, no advertencias. También sugiero promover las advertencias Unicode en excepciones, así que use ambas líneas, no solo una de ellas. Nota sin embargo que bajo v5.14, la
utf8
clase de aviso comprende otros tres subwarnings la que todos se pueden activar por separado:nonchar
,surrogate
, ynon_unicode
. Es posible que desee ejercer un mayor control sobre estos.Declare que esta unidad fuente está codificada como UTF ‑ 8. Aunque alguna vez este pragma hizo otras cosas, ahora sirve solo a este propósito singular y no a otro:
Declare que todo lo que abre un identificador de archivo dentro de este ámbito léxico pero no en otro lugar es asumir que esa secuencia está codificada en UTF ‑ 8 a menos que usted indique lo contrario. De esa manera no afecta el código de otro módulo u otro programa.
Habilitar caracteres con nombre a través de
\N{CHARNAME}
.Si tiene un
DATA
identificador, debe establecer explícitamente su codificación. Si desea que esto sea UTF ‑ 8, diga:Por supuesto, no hay fin de otros asuntos con los que eventualmente te encuentres preocupado, pero estos serán suficientes para aproximar el objetivo estatal de "hacer que todo funcione con UTF-8", aunque para un sentido algo debilitado de esos términos.
Otro pragma, aunque no está relacionado con Unicode, es:
Es muy recomendable
🌴 🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪 🐁
🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 🐪 🎁
Mi propio repetitivo en estos días tiende a verse así:
🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 𝖙 🎅
Diciendo que "Perl debería [de alguna manera! ] habilitar Unicode de forma predeterminada "ni siquiera comienza a pensar en decir lo suficiente como para ser marginalmente útil en algún tipo de caso raro y aislado. Unicode es mucho más que un repertorio de personajes más grande; También es cómo todos esos personajes interactúan de muchas, muchas maneras.
Incluso las medidas mínimas simples que (algunas) personas piensan que quieren están garantizadas para romper miserablemente millones de líneas de código, código que no tiene oportunidad de "actualizarse" a su nueva y elegante modernidad de Brave New World .
Es mucho más complicado de lo que la gente finge. He pensado en esto muchísimo en los últimos años. Me encantaría que me demuestren que estoy equivocado. Pero no creo que lo sea. Unicode es fundamentalmente más complejo que el modelo que le gustaría imponerle, y aquí hay una complejidad que nunca 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 desglosar y aprender de qué se trata Unicode. No puedes fingir que es algo que no es.
🐪 hace todo lo posible para que Unicode sea fácil, mucho más que cualquier otra cosa que haya usado. Si crees que esto es malo, intenta algo más por un tiempo. Luego regrese a 🐪: o habrá regresado a un mundo mejor, o de lo contrario traerá el conocimiento de lo mismo para que podamos utilizar su nuevo conocimiento para mejorar make en estas cosas.
💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖎𝖘𝖙 💡
Como mínimo, aquí hay algunas cosas que parecen ser necesarias para que 🐪 "habilite Unicode de forma predeterminada", como lo dice:
Todo el código fuente debe estar en UTF-8 por defecto. Puedes conseguir eso con
use utf8
oexport PERL5OPTS=-Mutf8
.El
DATA
mango 🐪 debe ser UTF-8. Tendrá que hacer esto por paquete, como enbinmode(DATA, ":encoding(UTF-8)")
.Los argumentos del programa para los scripts should deben entenderse como UTF-8 por defecto.
export PERL_UNICODE=A
, operl -CA
, oexport PERL5OPTS=-CA
.Los flujos de entrada, salida y error estándar deben ser UTF-8 predeterminados.
export PERL_UNICODE=S
para todos ellos, oI
,O
y / oE
solo para algunos de ellos. Esto es comoperl -CS
.Cualquier otra manija abierta por 🐪 debe considerarse UTF-8 a menos que se declare lo contrario;
export PERL_UNICODE=D
o coni
yo
para algunos particulares de estos;export PERL5OPTS=-CD
trabajaría. Eso los hace-CSAD
a todos.Cubre ambas bases más todas las transmisiones con las que abres
export PERL5OPTS=-Mopen=:utf8,:std
. Ver uniquote .No quiere perderse los errores de codificación UTF-8. Tratar
export PERL5OPTS=-Mwarnings=FATAL,utf8
. Y asegúrese de que sus flujos de entrada estén siempre enbinmode
d:encoding(UTF-8)
, no solo en:utf8
.Points debe entender que los puntos de código entre 128–255 son los puntos de código Unicode correspondientes, no solo los valores binarios sin propiedad.
use feature "unicode_strings"
oexport PERL5OPTS=-Mfeature=unicode_strings
. Eso haráuc("\xDF") eq "SS"
y"\xE9" =~ /\w/
. Un simpleexport PERL5OPTS=-Mv5.12
o mejor también lo conseguirá.Los caracteres Unicode con nombre no están habilitados de forma predeterminada, por lo tanto, agregue
export PERL5OPTS=-Mcharnames=:full,:short,latin,greek
o algo por el estilo. Ver uninames y tcgrep .Casi siempre necesita acceso a las funciones del módulo estándar de
Unicode::Normalize
varios tipos de descomposiciones.export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD
, y luego siempre ejecuta material entrante a través de NFD y material saliente de NFC. Todavía no conozco ninguna capa de E / S para estas, pero vea nfc , nfd , nfkd y nfkc .Comparaciones de cadenas en 🐪 usando
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 tuexport PERL5OPTS=-MUnicode::Collate
. Puede almacenar en caché la clave para las comparaciones binarias.🐪 a los incorporados les gusta
printf
ywrite
hacen lo incorrecto con los datos Unicode. Debe usar elUnicode::GCString
módulo para el primero, y tanto eso como también elUnicode::LineBreak
módulo para el segundo. Ver uwc y unifmt .Si quieres que cuenten como enteros, entonces tendrás que ejecutar tus
\d+
capturas a través de laUnicode::UCD::num
función porque el atoi incorporado (3) de 🐪 no es lo suficientemente inteligente.Tendrá problemas con el sistema de archivos en ystems sistemas de archivos. Algunos sistemas de archivos aplican 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 lleva a problemas aún mayores. Entonces debe hacer su propio manejo de NFC / NFD para mantenerse cuerdo.
Toda su 🐪 código que implica
a-z
oA-Z
, y tal debe ser cambiado , incluyendom//
,s///
ytr///
. Debe destacarse como una bandera roja que grita que su código está roto. Pero no está claro cómo debe cambiar. Obtener las propiedades correctas y comprender sus pliegues de casos es más difícil de lo que piensas. Yo uso unichars y uniprops todos los días.El código que usa
\p{Lu}
es casi tan incorrecto como el código que usa[A-Za-z]
. Necesita usar\p{Upper}
en su lugar, y saber el motivo. Sí,\p{Lowercase}
y\p{Lower}
son diferentes de\p{Ll}
y\p{Lowercase_Letter}
.El código que usa
[a-zA-Z]
es aún peor. Y no puede usar\pL
o\p{Letter}
; tiene que utilizar\p{Alphabetic}
. ¡No todos los alfabéticos son letras, sabes!Si está buscando variables 🐪 con
/[\$\@\%]\w+/
, entonces tiene un problema. Debe buscar/[\$\@\%]\p{IDS}\p{IDC}*/
, e incluso eso no es pensar en las variables de puntuación o las variables del paquete.Si está buscando espacios en blanco, debe elegir entre
\h
y\v
, dependiendo. Y nunca debe usar\s
, ya que NO SIGNIFICA[\h\v]
, contrario a la creencia popular.Si está utilizando
\n
un límite de línea, o incluso\r\n
, entonces lo está haciendo mal. Tienes que usar\R
, que no es lo mismo!Si no sabe cuándo y si llamar a Unicode :: Stringprep , será mejor que aprenda.
Las comparaciones que no distinguen entre mayúsculas y minúsculas deben verificar si dos cosas son las mismas letras sin importar sus signos diacríticos y demás. La forma más fácil de hacerlo es con el módulo estándar Unicode :: Collate .
Unicode::Collate->new(level => 1)->cmp($a, $b)
. También hayeq
métodos y tal, y probablemente también debería aprender sobre los métodosmatch
ysubstr
. Estos tienen ventajas distintas sobre los 🐪 integrados.A veces eso todavía no es suficiente, y necesita el módulo Unicode :: Collate :: Locale en su lugar, como en su
Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)
lugar. Considere que esoUnicode::Collate::->new(level => 1)->eq("d", "ð")
es cierto, peroUnicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")
es falso. Del mismo modo, "ae" y "æ" soneq
si no usa locales, o si usa el inglés, pero son diferentes en el local islandés. ¿Ahora que? Es difícil, te digo. Puedes jugar con ucsort para probar algunas de estas cosas.Considere cómo hacer coincidir el patrón CVCV (consonante, vocal, consonante, vocal) en la cadena " niño ". Su forma NFD, que más te conviene haber recordado, se convierte en "nin \ x {303} o". ¿Ahora que vas a hacer? Incluso fingiendo que una vocal es
[aeiou]
(lo cual es incorrecto, por cierto), tampoco podrás hacer algo así(?=[aeiou])\X)
, porque incluso en NFD un punto de código como 'ø' no se descompone . Sin embargo, probará 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 un millón de suposiciones rotas que la gente hace sobre Unicode. Hasta que entiendan estas cosas, su código 🐪 se romperá.
El código que supone que puede abrir un archivo de texto sin especificar que la codificación está rota.
El código que asume que la codificación predeterminada es algún tipo de codificación de plataforma nativa está roto.
El código que supone que las páginas web en japonés o chino ocupan menos espacio en UTF-16 que en UTF-8 es incorrecto.
El código que supone que Perl usa UTF ‑ 8 internamente es incorrecto.
El código que supone que los errores de codificación siempre generarán una excepción es incorrecto.
El código que supone que los puntos de código Perl están limitados a 0x10_FFFF es incorrecto.
El código que supone que puede establecer
$/
algo que funcionará con cualquier separador de línea válido es incorrecto.El código que supone la igualdad de ida y vuelta en el plegado de mayúsculas y minúsculas, como
lc(uc($s)) eq $s
ouc(lc($s)) eq $s
, está completamente roto e incorrecto. Tenga en cuenta queuc("σ")
yuc("ς")
son ambos"Σ"
, perolc("Σ")
no puede devolver ambos.El código que asume que cada punto de código en minúscula tiene uno en mayúscula distinto, o viceversa, está roto. Por ejemplo,
"ª"
es una letra minúscula sin mayúscula; mientras que tanto"ᵃ"
y"ᴬ"
son cartas, pero son letras minúsculas no; sin embargo, ambos son puntos de código en minúsculas sin las versiones en mayúsculas correspondientes. ¿Lo tengo? Son no\p{Lowercase_Letter}
, a pesar de ser a la vez\p{Letter}
y\p{Lowercase}
.El código que supone cambiar el caso no cambia la longitud de la cadena está rota.
El código que supone que solo hay dos casos está roto. También hay un título.
El código que supone que solo las letras tienen mayúsculas y minúsculas está roto. Más allá de las letras, resulta que los números, los símbolos e incluso las marcas tienen mayúsculas y minúsculas. De hecho, cambiar el caso puede incluso hacer que algo cambie su categoría general principal, como
\p{Mark}
convertirse en un\p{Letter}
. También puede hacer que cambie de un script a otro.El código que supone que el caso nunca depende de la configuración regional está roto.
El código que supone que Unicode da un higo sobre las configuraciones regionales POSIX está roto.
El código que supone que puede eliminar los signos diacríticos para obtener las letras ASCII básicas es malo, inmóvil, roto, con daño cerebral, incorrecto y justifica la pena capital.
El código que asume que los
\p{Diacritic}
signos diacríticos y las marcas\p{Mark}
son lo mismo está roto.Código que asume las
\p{GC=Dash_Punctuation}
cubiertas tanto como\p{Dash}
está roto.El código que supone que el guión, los guiones y las desventajas son lo mismo entre sí, o que solo hay uno de cada uno, está roto e incorrecto.
El código que supone que cada punto de código ocupa no más de una columna de impresión está roto.
El código que supone que todos los
\p{Mark}
caracteres ocupan cero columnas de impresión está roto.El código que supone que los caracteres que se parecen son iguales está roto.
El código que se supone que los caracteres que no no se parecen son no por igual se rompe.
El código que supone que hay un límite en el número de puntos de código en una fila que solo uno
\X
puede coincidir es incorrecto.Código que asume
\X
nunca puede comenzar con un\p{Mark}
personaje es incorrecto.Código que asume que
\X
nunca puede contener dos\p{Mark}
caracteres está mal.Código que asume que no puede usar
"\x{FFFF}"
está mal.El código que asume un punto de código no BMP que requiere dos unidades de código UTF-16 (sustituto) se codificará en dos caracteres UTF-8 separados, uno por unidad de código, es incorrecto. No lo hace: codifica a un solo punto de código.
El código que transcodifica desde UTF ‐ 16 o UTF ‐ 32 con listas de materiales principales en UTF ‐ 8 se rompe si coloca una lista de materiales al comienzo del UTF-8 resultante. Esto es tan estúpido que el ingeniero debería quitarse los párpados.
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 cree que la codificación U + 0000 como
"\xC0\x80"
está UTF-8 está rota y es incorrecta. Estos chicos también merecen el tratamiento de los párpados.El código que asume que los caracteres como
>
siempre apuntan a la derecha y<
siempre apuntan a la izquierda están mal, porque de hecho no lo hacen.Código que asume si primero imprime el carácter
X
y luego el carácterY
, que aparecerán comoXY
incorrectos. A veces no lo hacen.El código que asume que ASCII es lo suficientemente bueno para escribir inglés correctamente es estúpido, miope, analfabeto, roto, malvado y equivocado. ¡Afuera con sus cabezas! Si eso parece demasiado extremo, podemos comprometernos: en adelante, pueden escribir solo con el dedo gordo del pie. (El resto será grabado con ductos)
El código que supone que todos los
\p{Math}
puntos de código son caracteres visibles es incorrecto.El código que se supone
\w
contiene solo letras, dígitos y guiones bajos es incorrecto.El código que supone eso
^
y~
son signos de puntuación está mal.El código que supone que
ü
tiene una diéresis está mal.El código que cree que las cosas
₨
contienen letras en ellas está mal.El código que cree
\p{InLatin}
es el mismo que\p{Latin}
se rompe atrozmente.El código que cree que
\p{InLatin}
casi siempre es útil es casi seguro que está malCódigo que cree que dada
$FIRST_LETTER
como la primera letra en algún alfabeto y$LAST_LETTER
como la última letra en ese mismo alfabeto, que[${FIRST_LETTER}-${LAST_LETTER}]
tiene algún significado casi siempre está completamente rota, equivocada y sin sentido.El código que cree que el nombre de alguien solo puede contener ciertos caracteres es estúpido, ofensivo e incorrecto.
El código que intenta reducir Unicode a ASCII no es simplemente incorrecto, nunca se debe permitir que su autor vuelva a trabajar en la programación. Período. Ni siquiera estoy seguro de que se les permita ver de nuevo, ya que obviamente no les ha hecho mucho bien hasta ahora.
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. También podría sacar el otro ojo.
El código que convierte caracteres desconocidos en
?
está roto, es estúpido, no funciona y es contrario a la recomendación estándar, que dice ¡ NO HACER ESO!RTFM por qué no.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 solucionará un rayo de Zeus.
Código que cree que puede usar 🐪
printf
anchuras para rellenar y justificar que los datos Unicode estén rotos y sean incorrectos.El código que cree una vez que crea con éxito un archivo con un nombre determinado, que cuando ejecuta
ls
oreaddir
en su directorio adjunto, en realidad encontrará que el archivo con el nombre con el que lo creó está defectuoso, roto e incorrecto. ¡Deja de sorprenderte por esto!El código que cree que UTF-16 es una codificación de ancho fijo es estúpido, roto e incorrecto. Revocar su licencia de programación.
El código que trata los puntos de código de un plano de manera diferente a los de cualquier otro plano está ipso facto roto e incorrecto. Volver a la escuela.
Código que cree que cosas como
/s/i
solo pueden coincidir"S"
o"s"
están rotas y mal. Te sorprenderias.El código que se usa
\PM\pM*
para encontrar grupos de grafemas en lugar de usar\X
está roto y es incorrecto.Las personas que desean regresar al mundo ASCII deben ser animadas de todo corazón a hacerlo, y en honor a su gloriosa actualización, se les debe proporcionar gratis una máquina de escribir manual pre-eléctrica para todas sus necesidades de ingreso de datos. Los mensajes que se les envíen deben enviarse a través de un telégrafo a 40 caracteres por línea y entregados personalmente por un servicio de mensajería. DETENER.
😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄 😱
No sé cuánto más puede obtener "Unicode predeterminado en you" de lo que he escrito. Bueno, sí lo hago: deberías estar usando
Unicode::Collate
yUnicode::LineBreak
también. Y probablemente más.Como se ve, hay demasiadas cosas Unicode que realmente no tiene que preocuparse de que haya alguna vez existe tal cosa como “por defecto a Unicode”.
Lo que va a descubrir, tal como lo hicimos en 🐪 5.8, que es simplemente imposible imponer todas estas cosas en el código que no ha sido diseñado desde el principio para darles cuenta. Tu egoísmo bien intencionado acaba de romper el mundo entero.
E incluso una vez que lo haga, todavía hay problemas críticos que requieren una gran cantidad de pensamiento para hacerlo bien. No hay un interruptor que pueda activar. Nada más que cerebro, y quiero decir cerebro real , será suficiente aquí. Hay muchas cosas que tienes que aprender. Modulo del retiro a la máquina de escribir manual, simplemente no puede esperar escabullirse por ignorancia. Este es el siglo XXI, y no puedes desear que Unicode se vaya por ignorancia voluntaria.
Tienes que aprenderlo. Período. Nunca será tan fácil que "todo simplemente funciona", porque eso garantizará que muchas cosas no funcionen funcionen, lo que invalida la suposición de que alguna vez puede haber una manera de "hacer que todo funcione".
Es posible que pueda obtener algunos valores predeterminados razonables para muy 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 ordenamiento canónico causará verdaderos dolores de cabeza. 😭
"\x{F5}"
'õ' ,"o\x{303}"
'õ' ,"o\x{303}\x{304}"
'ȭ' y"o\x{304}\x{303}"
'ō̃' deberían coincidir con 'õ' , pero ¿cómo 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 lo prometo: "̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲" 😞
No puede simplemente cambiar algunos valores predeterminados y obtener una navegación fluida. Es cierto que ejecuto 🐪 con
PERL_UNICODE
set to"SA"
, pero eso es todo, e incluso eso es principalmente para cosas de línea de comandos. Para un trabajo real, paso por todos los pasos descritos anteriormente, y lo hago muy, ** muy ** cuidadosamente.😈 ¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ ʻλɐp əɔᴉu ɐ əʌɐɥ ʻʞɔnl poo⅁ 😈
fuente
Hay dos etapas para procesar texto Unicode. El primero es "cómo puedo ingresarlo y generarlo 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 en su publicación. La mayoría de los programas ni siquiera manejan las E / S correctamente, por lo que es importante comprender eso antes de que empiece a preocuparse por la normalización y la clasificación.
Esta publicación tiene como objetivo resolver ese primer problema
Cuando lees datos en Perl, no importa qué codificación tenga. Asigna un poco de memoria y guarda los bytes allí. Si usted dice
print $str
, simplemente borra esos bytes a su terminal, que probablemente está configurado para asumir que todo lo que está escrito en él es UTF-8, y su texto aparece.Maravilloso.
Excepto que no lo es. Si intenta tratar los datos como texto, verá que algo malo está sucediendo. No necesita ir más allá de
length
ver que lo que Perl piensa acerca de su cadena y lo que piensa acerca de su cadena no está de acuerdo. Escribe una frase como:perl -E 'while(<>){ chomp; say length }'
y escribe文字化け
y obtienes 12 ... no es 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
(ouse Encode qw(decode)
, por supuesto). Esa función toma una cadena del mundo exterior (lo que llamaremos "octetos", una forma elegante de decir "bytes de 8 bits"), y la convierte en un texto que Perl comprenderá. 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 Perl que contiene el texto.(También existe
Encode::decode_utf8
, lo que supone UTF-8 para la codificación).Si reescribimos nuestro one-liner:
Escribimos 文字 化 け y obtenemos "4" como resultado. Éxito.
Esa es la solución al 99% de los problemas de Unicode en Perl.
La clave es que cada vez que ingrese texto en su programa, debe 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 puedes tratar los octetos como caracteres en Perl. Debe decodificar los octetos codificados en caracteres Perl con el módulo Encode.
La otra mitad del problema es sacar datos de su programa. Eso es fácil de hacer; solo diga
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 envíe el resultado enencode($encoding, $data)
lugar de simplemente enviarlo$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 enviar caracteres a través de Internet o a nuestras terminales, pero no podemos: octetos solamente. Entonces tenemos que convertir caracteres a octetos, de lo contrario los resultados no están definidos.
Para resumir: codifique todas las salidas y decodifique todas las entradas.
Ahora hablaremos sobre tres problemas que hacen que esto sea un poco desafiante. El primero son las 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 es
decoded_content
, nocontent
, que es solo el flujo de octetos que obtuvo del servidor). Los controladores de la base de datos pueden ser escamosos; si usa DBD :: SQLite solo con Perl, funcionará, pero si alguna otra herramienta ha puesto texto almacenado como una codificación distinta de 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 en la impresión", entonces sabe que está confundiendo la codificación en alguna parte. Esa advertencia significa "oye, estás tratando de filtrar personajes de Perl al mundo exterior y eso no tiene ningún sentido". Parece que su programa funciona (porque el otro extremo generalmente maneja los caracteres de 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 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ímy $var = 'ほげ'
, estás inyectando basura en tu programa que romperá todo horriblemente. No tiene que "usar utf8", pero si no lo hace, no debe usar 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 el Unicode, y Perl asumió que todo era texto o binario latino-1. Entonces, cuando los datos ingresan a su programa y comienza a tratarlos como texto, Perl trata cada octeto como un carácter latino-1. Es por eso que, cuando preguntamos por la longitud de "文字 化 け", obtuvimos 12. Perl asumió que estábamos operando en la cadena latina-1 "æååã" (que tiene 12 caracteres, algunos de los cuales no se imprimen).
Esto se llama una "actualización implícita", y es una cosa perfectamente razonable de hacer, pero no es lo que desea si su texto no es latino-1. Es por eso que es crítico decodificar explícitamente la entrada: si no lo hace, Perl lo hará, y podría hacerlo mal.
Las personas se encuentran 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 texto latino-1 y luego la combinará con los datos de caracteres correctos. Esto hará que parezca que manejar tus personajes correctamente rompió tu programa, pero en realidad, simplemente no lo has solucionado lo suficiente.
Aquí hay un ejemplo: tiene un programa que lee un archivo de texto codificado en UTF-8, pega un Unicode
PILE OF POO
en cada línea y lo imprime. Lo escribes como:Y luego ejecuta algunos datos codificados UTF-8, como:
Imprime los datos UTF-8 con una caca al final de cada línea. Perfecto, mi programa funciona!
Pero no, solo estás haciendo una concatenación binaria. Estás leyendo octetos del archivo, eliminando a
\n
con chomp y luego añadiendo los bytes en la representación UTF-8 delPILE OF POO
personaje. Cuando revise su programa para decodificar los datos del archivo y codifique la salida, notará que obtiene basura ("ð ©") en lugar de la caca. Esto lo llevará a creer que decodificar el archivo de entrada es algo incorrecto. No es.El problema es que la caca se está actualizando implícitamente como latin-1. Si desea
use utf8
hacer el texto literal en lugar de binario, ¡funcionará nuevamente!(Ese es el problema número uno que veo cuando ayudo a las personas con Unicode. Se separaron bien y eso rompió su programa. Eso es lo triste de los resultados indefinidos: puedes tener un programa que funciona durante mucho tiempo, pero cuando comienzas a repararlo, se rompe. No se preocupe; si agrega declaraciones de codificación / decodificación a su programa y se rompe, solo significa que tiene más trabajo que hacer. La próxima vez, cuando diseñe con Unicode en mente desde el principio, será ¡más fácil!)
Eso es realmente todo lo que necesita saber sobre Perl y Unicode. Si le dice a Perl cuáles son sus datos, tiene el mejor soporte Unicode entre todos los lenguajes de programación populares. Sin embargo, si asume que mágicamente sabrá qué tipo de texto lo está alimentando, entonces va a tirar a la basura 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 UTF-16. ¡Así que hazlo seguro ahora y ahórrate el dolor de cabeza de destrozar los datos de tus usuarios!
La parte fácil de manejar Unicode es codificar la salida y decodificar la entrada. La parte difícil es encontrar todas sus entradas y salidas, y determinar qué codificación es. Pero es por eso que obtienes mucho dinero :)
fuente
Encode
módulo es tedioso y propenso a errores, y hace que leer el código sobre E / S sea realmente doloroso. Las capas de E / S proporcionan una solución, ya que codifican y decodifican de forma transparente, cuando es necesario.open
ybinmode
permite su especificación, y pragmaopen
establece los valores predeterminados, como tchrist recomienda en su respuesta.Todos estamos de acuerdo en que es un problema difícil por muchas razones, pero esa es precisamente la razón para intentar facilitarlo a todos.
Hay un módulo reciente en CPAN, utf8 :: all , que intenta "activar Unicode. Todo".
Como se ha señalado, mágicamente no puede hacer que todo el sistema (programas externos, solicitudes web externas, etc.) también use Unicode, pero podemos trabajar juntos para crear herramientas sensibles que faciliten la solució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 lo mejor posible.
``
fuente
utf8::all
módulo citado . Fue escrito antes de launicode_strings
función, que Fɪɴᴀʟʟʏ ᴀɴᴅ ᴀᴛ Lᴏɴɢ Lᴀsᴛ corrige las expresiones regulares para/u
tenerlas. No estoy convencido de que genere una excepción en los errores de codificación, y eso es algo que realmente debe tener. No se carga en eluse charnames ":full"
pragma, que aún no se carga automáticamente. No advierte[a-z]
y,printf
anchos de cadena, usando en\n
lugar de\R
y en.
lugar de\X
, pero tal vez sean más unPerl::Critic
problema. Si fuera yo, agregaría 𝐍𝐅𝐃 dentro y 𝐍𝐅𝐂 fuera.unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r
. Del mismo modo, pequeños pasos de preprocesamiento como... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'
pueden ser realmente buenos también, y no quisiera tomar las decisiones de otros por ellos. Todavía estoy construyendo mi caja de herramientas Unicode .Creo que no entiendes a Unicode y su relación con Perl. No importa de qué manera almacene los datos, Unicode, ISO-8859-1 o muchas otras 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 ) Obtenga esa interpretación incorrecta y confunde los datos. No hay una configuración mágica predeterminada dentro de su programa que le dirá a las cosas 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 tenía que interactuar. Si todo usara nada más que 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 desea que su manejador de entrada piense que está obteniendo octetos UTF-8 a menos que realmente lo sea, y no desea que sus manejadores de salida sean UTF-8 si la cosa que lee de ellos puede manejar UTF-8 . Perl no tiene forma de saber esas cosas. Por eso 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 Con ese fin, puse Unicode en Learning Perl, sexta edición , y hay muchas cosas de Unicode en la programación efectiva de Perl . Tienes que pasar el tiempo para aprender y comprender Unicode y cómo funciona. De lo contrario, no podrá utilizarlo de manera efectiva.
fuente
use utf8_everywhere
hace feliz a la gente. ¿Por qué no el último?Al leer 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 las diversas "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 (así como todas las demás codificaciones ) existe y solo tiene significado en la entrada o 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 funciones que se cubrieron con admiración anteriormente.
fuente
Hay una cantidad realmente horrible de código antiguo en la naturaleza, en gran parte en forma de módulos CPAN comunes. Descubrí que tengo que tener bastante cuidado al habilitar Unicode si uso módulos externos que podrían verse afectados, y todavía estoy tratando de identificar y corregir algunas fallas relacionadas 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).
fuente
-C
opción para asegurarme de que Perl esté en la misma página que yo en cuanto a Unicode, porque sigo teniendo que decida usar ISO 8859/1 en lugar de Unicode a pesar de que estoy configurando explícitamente$LANG
y$LC_ALL
correctamente. (Esto en realidad puede reflejar errores en las bibliotecas locales de la plataforma). Sea lo que sea, ha sido muy molesto que no pueda usar iTivo en programas con acentos porque los scripts de Perl que hacen el trabajo se caen con errores de conversión.-C
sin opciones tiene errores y es propenso a errores . Rompes el mundo. Establezca laPERL5OPT
variable en-C
y verá lo que quiero decir. Lo intentamos de vuelta en v5.8, y fue un desastre. Simplemente no puede ni debe decirle a los programas que no lo esperan que ahora están tratando con Unicode, les guste o no. También hay problemas de seguridad. Por lo menos, todo lo que hagaprint while <>
se romperá si se pasan datos binarios. También lo hará todo el código de la base de datos. Esta es una idea terrible.-C
sin opciones. La invocación específica con la que había estado trabajando era-CSDA
. Dicho esto, estuve atascado con 5.8.x durante mucho tiempo (hola MacPorts ...), así que tal vez eso fue parte de eso.Debe habilitar la función de cadenas Unicode, y esta es la predeterminada si usa v5.14;
Realmente no deberías usar identificadores Unicode especialmente. para el código extranjero a través de utf8, ya que no son seguros en perl5, solo cperl lo hizo bien. Ver, por ejemplo, http://perl11.org/blog/unicode-identifiers.html
Con respecto a utf8 para sus manejadores / secuencias de archivos: debe decidir usted mismo la codificación de sus datos externos. Una biblioteca no puede saber eso, y dado que ni siquiera libc admite utf8, los datos adecuados de utf8 son raros. Hay más wtf8, la aberración de windows de utf8 alrededor.
Por cierto: Moose no es realmente "Modern Perl", simplemente secuestraron el nombre. Moose es perfecto Perl posmoderno estilo Larry Wall mezclado con estilo Bjarne Stroustrup todo funciona, con una aberración ecléctica de la sintaxis perl6 adecuada, por ejemplo, el uso de cadenas para nombres de variables, 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.
fuente