Ключевые слова:perl, unicode, charset, translate, (найти похожие документы)
Date: Thu, 28 Nov 2002 19:40:56 +0500
From: Andrey Sapozhnikov <[email protected]>
Newsgroups: ftn.ru.perl
Subject: Преобразование utf8 кода Perl на выходе в koi8-r + HTML
> "\x{2020}Сегодня\x{A0}\x{2014} Geschlo\x{DF}en"
>
> Результат может быть в любой восьмибитной кодировке, в которой нет
> символов EM-DASH, BULLET и западно-европейских акцентированных букв.
> Hапример, в кои-8. С неразрывным пробелом там призовая игра, ибо он в
> кодировки есть.
>> как \x{NNNN}. И в какой кодировке Вы хотите результат? Ибо то, что
>> я вижу вообще не есть перекодировка чарсетов.
> Согласен. Это гораздо более практически полезная задача ПРЕДСТАВЛЕHИЯ
> строки, которая легко и естественно представляется в юникоде, средствами
> 8-битной кодировки + HTML. Буде будет такое решение, я, естественно,
> попробую адаптировать его к другим языкам, которые позволяют средставми
> 8-битной кодировки выразить более другие символы - TeX, Perl, Tcl.
> Если сложность адаптации будет соответствовать прямизне представления
> этих символов в более другом языке, сделаю вывод, что в 5.8 перле
> работа с кодировками сделана УДОБHО.
======================== example ==========================
#!/usr/bin/perl -w
use strict;
BEGIN {
use utf8;
package Encode::myhtml;
use base qw(Encode::Encoding);
__PACKAGE__->Define('myhtml');
my %subst = (
'&' => '&', '<' => '<', '>' => '>', '"' => '"',
"\x{00a0}" => ' ', "\x{2014}" => '—', "\x{00df}" => 'ss'
);
sub encode ($$;$) {
(my $str = $_[1]) =~ s/([&<">\x{0080}-\x{ffff}])/$subst{$1} || $1/ge;
$_[1] = '' if $_[2];
Encode::encode('koi8-r', $str, Encode::FB_HTMLCREF);
}
};
use utf8;
use encoding 'utf8', STDOUT => 'myhtml';
print "\x{2020}п║п╣пЁп╬п╢п╫я▐\x{A0}\x{2014} Geschlo\x{DF}en";
======================== eof ==========================
Вот, пожалуйста. Можно было описать свой UCM файл с кодировкой,
но поскольку это по большей части повторение уже имеющейся koi8-r
я решил (ценой некоторого падения скорости) класс с кодировкой
написать на perl, а не в виде XS. Hадеюсь, что в твой экран
оно влезет. Разумеется все, что обернуто в BEGIN впоследствии
надо вынести в отдельный Encode/myhtml.pm который сам вызовется
при необходимости. То, что стоит в print - это и есть твоя строка.
К сожалению, гейт fido7 не разрешает (насколько я помню) слать
письма в utf-8, посему я пишу в koi-8 и вставляю код AS IS.
Если что-то поломается - открой скрипт любым редактором
поддерживающим utf-8 и поправь строчку :)
From: Andrey Sapozhnikov <[email protected]>
> AS> my $koi = find_encoding('koi8-r') or die "Encoding koi8-r not found";
> AS> my $encoded = $koi->encode($line, Encode::FB_QUIET);
>
> В таком варианте - работает. Только почему-то пока я задавал элементы
> массива подстановок как "\x{00df}"=>'ss'
> не хотело подставлять эсцет.
> Как я поменял индексы хеша на ord-ы от соответствующего символа - все
> заработало.
perldoc perlunicode
...
Unicode characters can also be added to a string by using the
"\x{...}" notation. The Unicode code for the desired character, in
hexadecimal, should be placed in the braces. For instance, a smiley
face is "\x{263A}". This encoding scheme only works for characters
with a code of 0x100 or above.
...
посему строка с одним символом \xDF который может быть представлен
в 8 битах с целью совместимости остается байтовой. А потом при апгрейде
транслируется в уникодное представление символа \xDF которое есть не
\x{00DF}. F*cking legacy. Hо в большинстве случаев это должно сказываться
только при неправильно выставленном флажке utf8 (например считали из
raw источника utf8 строку и не декодировали. Или при злонамеренном
побайтовом сравнении вместо посимвольного). В таком случае можно
строку явно пометить с помощью Encode::_utf8_on, хотя корректнее
все-таки декодировать (decode('utf8', $line)).
> Hо ведь что обидно - вчерашний вариант с необъектным интерфейсом я из
> perldoc Encode передирал.
только там в примере decode, а не encode было. :)
Андрей
P.S. Медитируем над результатами скрипта:
#!/usr/bin/perl -w
use strict;
use utf8;
use Encode;
my $a = "\xdf";
my $b = "\x{00df}";
my $c = "\x{01df}";
my $d = chr(0xdf);
my $e = pack('U', 0xdf);
my $f = substr("\x{00df}", -1, 1);
my $g = substr("\x{01df}\x{00df}", -1, 1);
my $h = "\x{01df}\x{00df}"; Encode::_utf8_off($h); $h = substr($h, -1, 1);
print '$a is ', Encode::is_utf8($a) ? "utf8\n" : "bytes\n";
print '$b is ', Encode::is_utf8($b) ? "utf8\n" : "bytes\n";
print '$c is ', Encode::is_utf8($c) ? "utf8\n" : "bytes\n";
print '$d is ', Encode::is_utf8($d) ? "utf8\n" : "bytes\n";
print '$e is ', Encode::is_utf8($e) ? "utf8\n" : "bytes\n";
print '$f is ', Encode::is_utf8($f) ? "utf8\n" : "bytes\n";
print '$g is ', Encode::is_utf8($g) ? "utf8\n" : "bytes\n";
print '$h is ', Encode::is_utf8($h) ? "utf8\n" : "bytes\n";
print "\n==== chars ====\n";
print '$a, $b -> ', $a eq $b ? "eq\n" : "ne\n";
print '$b, $f -> ', $b eq $f ? "eq\n" : "ne\n";
print '$f, $g -> ', $f eq $g ? "eq\n" : "ne\n";
print '$g, $h -> ', $g eq $h ? "eq\n" : "ne\n";
printf("ord(\$a) = %x\n", ord($a));
printf("ord(\$b) = %x\n", ord($b));
printf("ord(\$c) = %x\n", ord($c));
printf("ord(\$d) = %x\n", ord($d));
printf("ord(\$e) = %x\n", ord($e));
printf("ord(\$f) = %x\n", ord($f));
printf("ord(\$g) = %x\n", ord($g));
printf("ord(\$h) = %x\n", ord($h));
use bytes;
print "\n==== bytes ====\n";
print '$a, $b -> ', $a eq $b ? "eq\n" : "ne\n";
print '$b, $f -> ', $b eq $f ? "eq\n" : "ne\n";
print '$f, $g -> ', $f eq $g ? "eq\n" : "ne\n";
print '$g, $h -> ', $g eq $h ? "eq\n" : "ne\n";
printf("ord(\$a) = %x\n", ord($a));
printf("ord(\$b) = %x\n", ord($b));
printf("ord(\$c) = %x\n", ord($c));
printf("ord(\$d) = %x\n", ord($d));
printf("ord(\$e) = %x\n", ord($e));
printf("ord(\$f) = %x\n", ord($f));
printf("ord(\$g) = %x\n", ord($g));
printf("ord(\$h) = %x\n", ord($h));