¿Por qué me repito el último octeto cuando mi programa Perl genera una cadena codificada en UTF-8 en cmd.exe?
windows (1)
El siguiente programa produce la salida correcta:
use utf8;
use strict;
use warnings;
use warnings qw(FATAL utf8);
binmode(STDOUT, ":unix:encoding(utf8):crlf");
print ''αβγxyz'', "/n";
Salida:
C:/…> chcp 65001 Active code page: 65001 C:/…> perl pttt.pl αβγxyz
lo que parece indicarme que hay algo raro con la capa :crlf
. No entiendo los aspectos internos lo suficiente como para comentar inteligentemente sobre esto en este momento.
Después de muchos experimentos, llegué a la conclusión de que, si la consola ya está configurada en la página de códigos 65001, binmode(STDOUT, ":unix:encoding(utf8):crlf");
trabajará". Sin embargo, tenga en cuenta lo siguiente:
binmode(STDOUT, ":unix:encoding(utf8):crlf");
print Dump [
map {
my $x = defined($_) ? $_ : '''';
$x =~ s//A([0-9]+)/z/sprintf ''0x%08x'', $1/eg;
$x;
} PerlIO::get_layers(STDOUT, details => 1)
];
print "αβγxyz/n";
me da
--- - unix - '''' - 0x01205200 - crlf - '''' - 0x00c85200 - unix - '''' - 0x01201200 - encoding - utf8 - 0x00c89200 - crlf - '''' - 0x00c8d200 αβγxyz
Como antes, no sé lo suficiente como para saber las consecuencias de esto. Tengo la intención de construir un perl
depuración en algún momento para diagnosticar esto.
Examiné esto un poco más lejos . Aquí hay algunas observaciones de ese post:
Las banderas para la primera capa de unix
son 0x01205200 = CANWRITE | TRUNCATE | CRLF | OPEN | NOTREG
0x01205200 = CANWRITE | TRUNCATE | CRLF | OPEN | NOTREG
0x01205200 = CANWRITE | TRUNCATE | CRLF | OPEN | NOTREG
. ¿Por qué se establece CRLF
para la capa de unix
en Windows? No sé lo suficiente sobre los aspectos internos para entender esto.
Sin embargo, las banderas para la segunda capa de unix
, la que presiona mi modo de binmode
explícito, son 0x01201200 = 0x01205200 y ~ CRLF. Esto es lo que para mí tendría sentido para empezar.
Las banderas para la primera capa 0x00c85200 = CANWRITE | TRUNCATE | CRLF | LINEBUF | FASTGETS | TTY
son 0x00c85200 = CANWRITE | TRUNCATE | CRLF | LINEBUF | FASTGETS | TTY
0x00c85200 = CANWRITE | TRUNCATE | CRLF | LINEBUF | FASTGETS | TTY
0x00c85200 = CANWRITE | TRUNCATE | CRLF | LINEBUF | FASTGETS | TTY
. Las banderas para la segunda layer
, que :encoding(utf8)
después de la capa :encoding(utf8)
son 0x00c8d200 = 0x00c85200 | UTF8
0x00c8d200 = 0x00c85200 | UTF8
.
Ahora, si abro un archivo usando open my $fh, ''>:encoding(utf8)'', ''ttt''
, y vuelco la misma información, obtengo:
--- - unix - '''' - 0x00201200 - crlf - '''' - 0x00405200 - encoding - utf8 - 0x00409200
Como se esperaba, la capa de unix
no establece el indicador CRLF
.
Actualizar
Como sugirió @ikegami, informé esto como un error.
Considere los siguientes programas de C y Perl que dan salida a la codificación UTF-8 de la cadena "αβγ" en la salida estándar:
Versión C:
#include <stdio.h>
int main(void) {
/* UTF-8 encoded alpha, beta, gamma */
char x[] = { 0xce, 0xb1, 0xce, 0xb2, 0xce, 0xb3, 0x00 };
puts(x);
return 0;
}
Salida:
C:/…> chcp 65001 Active code page: 65001 C:/…> cttt.exe αβγ
Versión Perl:
C:/…> perl -e "print qq{/xce/xb1/xce/xb2/xce/xb3/n}" αβγ �
Por lo que puedo decir, el último octeto, 0xb3
está 0xb3
nuevo, en otra línea, que se está traduciendo a U+FFFD
.
Tenga en cuenta que redirigir la salida elimina este efecto.
También puedo verificar que es el último octeto que se repite:
C:/…> perl -e "print qq{/xce/xb1/xce/xb2/xce/xb3xyz/n}" αβγxyz z
Por otro lado, syswrite evita este problema.
C:/…> perl -e "syswrite STDOUT, qq{/xce/xb1/xce/xb2/xce/xb3xyz/n}" αβγxyz
He observado esto en las ventanas de cmd.exe en Windows 8.1 Pro de 64 bits y Windows Vista Home de 32 bits con Perl 5.18.2 y ActiveState 5.16.3.
No veo el problema en los entornos Cygwin, Linux o Mac OS X. Además, Perl 5.14.4 de Cygwin produce un resultado correcto en cmd.exe.
Además, cuando la página de códigos se establece en 437, la salida de las versiones C y Perl es idéntica:
C:/…> chcp 437 Active code page: 437 C:/…> cttt.exe ╬▒╬▓╬│ C:/…> perl -e "print qq{/xce/xb1/xce/xb2/xce/xb3/n}" ╬▒╬▓╬│
¿Qué hace que el último octeto se imprima dos veces cuando se imprime desde el programa perl en cmd.exe cuando la página de códigos está configurada en 65001 ?
PD: Tengo más información y capturas de pantalla en mi blog . Para esta pregunta, he tratado de destilar todo a los casos más simples posibles.
PPS: omitir los resultados de /n
en algo aún más interesante:
C:/…> perl -e "print qq{/xce/xb1/xce/xb2/xce/xb3xyz}" αβγxyzxyz
C:/…> perl -e "print qq{/xce/xb1/xce/xb2/xce/xb3}" αβγ�γ�