Смешивание декодирования HTML Entity с символами BIG5, преобразование в UTF-8 с использованием Perl

Мой сценарий Perl и файл ввода данных находятся в китайской кодировке BIG5.

Строковые данные содержат объект HTML, например. японские иероглифы

Результат отлично отображается при просмотре в браузере.

Но для дальнейших манипуляций с данными мне нужно преобразовать их все в UTF-8.

eg.

Из кодировки BIG5

一と三

В кодировку UTF-8

一と三

Вот код, который я пробовал:

#!/usr/local/bin/perl

use Encode qw/encode decode/;
use HTML::Entities;

print "Content-type: text/html\n\n";

$str = "と";
$str = encode('utf8', decode("big5",$str));
print "$str\n";
decode_entities($str);
print "$str\n";

$str2 = "一と三";
$str2 = encode('utf8', decode("big5",$str2));
print "$str2\n";
decode_entities($str2); # where the issue is
print "$str2\n";

Вот результат после запуска вышеуказанного кода.

と
と
一と三
ä¸とä¸

Обратите внимание, что сам скрипт также сохраняется в кодировке BIG5.

После decode_entities($str2); кажется, что он также пытается декодировать китайские символы в UTF-8, что и вызывает проблему.

Как решить эту проблему? Или ограничиться применением decode_entities() только к шаблону &xxxxx;?


person KDX    schedule 03.06.2016    source источник


Ответы (1)


Проблема в том, что вы смешиваете decode_entities, который выводит строку utf8 (utf8::is_utf8 возвращает true) с необработанной строкой (utf8::is_utf8 возвращает false), состоящей из потока октетов, который можно интерпретировать как utf8. Вместо этого вы должны комбинировать либо необработанные строки, либо строки utf8.

Следующее работает, сначала кодируя вашу строку из big5 в строку utf8, затем заменяя кодировки HTML и затем, наконец, преобразовывая все в необработанную строку, представляющую символы utf8:

$str2 = "一と三";
$str2 = decode("big5",$str2);  # big5 to internal utf8 -> utf8::is_utf8($str2) is true
decode_entities($str2);        # decode HTML entities
$str2 = encode('utf8',$str2);  # internal utf8 to raw bytes, utf8::is_utf8($str2) is false
person Steffen Ullrich    schedule 03.06.2016
comment
Отлично, это работает на моем тестовом образце. Но после запуска еще нескольких тестовых данных я обнаружил, что некоторые символы не работают, и я не мог понять, почему. Пожалуйста, посмотрите, сможете ли вы заставить его работать с этой строкой $str2 = "嶋一と三円"; Вывод должен быть 嶋一と三円, но теперь первый и последний символы становятся ? отметка - person KDX; 03.06.2016
comment
Эти символы HTML Entities отображаются правильно, если используется мой исходный код $str2 = encode('utf8', decode("big5",$str2)); (но с другими зашифрованными китайскими символами) - person KDX; 03.06.2016
comment
@KDX: ваш пример дает 嶋一と三円 для меня, так что это работает, по крайней мере, для меня. Пробовал с версиями perl 5.22.1, 5.12.5 и даже 5.8.9 с текущей версией HTML::Entities. Я понятия не имею, что вы используете и как выглядит ваш код. Я только что установил $str2 = "嶋一と三円" в своем примере кода. - person Steffen Ullrich; 03.06.2016
comment
На моем хостинге работает Perl 5.12.4, а HTML::Entities отображается как 3.69. Я использую точный тестовый код, который вы написали с объявлением use в моем исходном вопросе. Я нахожу это странным, потому что те же самые символы появляются при использовании $str2 = encode('utf8', decode("big5",$str2)); Какие версии вы используете в своей тестовой среде? - person KDX; 03.06.2016
comment
@KDX: HTML::Entities - это 3.69, но фактическая реализация decode_entities выполняется в некотором коде C в HTML::Parser. Версия HTML::Parser во всех случаях 3.72. - person Steffen Ullrich; 03.06.2016
comment
Я не совсем понимаю. Нужно ли использовать HTML::Parser в коде? Строковые данные, которые я собираюсь обработать, не содержат никакого HTML, а только обычный текст, содержащий поле данных и разделители. Я проверил с помощью perl -MHTML::Parser -e 'print $HTML::Parser::VERSION';, и он тоже дал мне 3,69. Будет ли версия Perl иметь значение? Спасибо. - person KDX; 03.06.2016
comment
@KDX: HTML::Entities является частью дистрибутива HTML::Parser. Функция decode_entities реализована не внутри модуля HTML::Entities, а в том же другом файле (util.c), поэтому версия самого модуля HTML::Entities не имеет значения. Версия Perl может иметь значение, но в данном случае я сомневаюсь, поскольку она работает для меня с текущим дистрибутивом HTML::Parser и Perl 5.8.9. - person Steffen Ullrich; 03.06.2016
comment
В этом случае вы предлагаете мне обновить HTML::Parser с 3.69 до 3.72, где decode_entities в util.c будут актуальны? Мне кажется, что только некоторые объекты HTML не конвертируются, иначе это работает в большинстве случаев. - person KDX; 04.06.2016
comment
@KDX: я бы попробовал. - person Steffen Ullrich; 04.06.2016