Да нахер этот Perl..

Mar 03, 2011 19:51

Это неинтересное, это про программирование.

Допустим, Вы - программист, пишущий на Perl. И вот приспичило Вам использовать в своих программах UTF-8.

Прочитали про внутреннее представление строк в Perl, про флажки-костыли, про управление ими... Начали с переменных:

use strict;
use warnings;
my $a = 'дададад!';
print($a, ' ', length($a));
^D
дададад! 15

Хм.. длина определилась неверно. Но мы-то знаем нужную прагму! Добавляем 'use utf8':

use strict;
use warnings;
use utf8;
my $a = 'дададад!';
print($a, ' ', length($a));
^D
Wide character in print at - line 5.
дададад! 8

Длина теперь верная, но появились странные предупреждения... А, надо этому Perl объяснить, что STDOUT (да и остальные STD*) - они готовы работать с UTF-8, объявим это через очередную "волшебную" прагму 'use open':

use strict;
use warnings;
use utf8;
use open qw{:std :utf8};
my $a = 'дададад!';
print($a, ' ', length($a));
^D
дададад! 8

На первый взгляд, всё красиво и правильно. Но мы ж настоящие программисты, мы ж такими hello-world'ами не ограничиваемся. Давайте что-нибудь "выдернем" из СУБД через DBI. Что-нибудь UTF'ное. =) Допустим, из MySQL. Допустим, табличка там имеет DEFAULT CHARSET=utf8. Допустим, удачно подключились, получили рабочий handler ($dbh), как вариант, сказали туда "SET NAMES utf8". Вытаскиваем:

my $sql = 'select key_id, name from key_pack where key_id = 1';
my @rc = $dbh->selectrow_array($sql);
print($rc[1], ' ', length($rc[1]), "\n");
^D
пакеÑик 14

Таааак.. Программа у нас UTF'ная, а DBI гонит какой-то raw-поток байтов. Придётся его подровнять. Напишем wrapper:

sub dbi_utf8_on_array
{
map {utf8::decode($_) unless utf8::is_utf8($_)} @_;
return @_;
}

my $sql = 'select key_id, name from key_pack where key_id = 1';
my @rc = dbi_utf8_on_array($dbh->selectrow_array($sql));
print($rc[1], ' ', length($rc[1]), "\n");
^D
пакетик 7

Вот, теперь порядок. Но мы ж можем использовать не только selectrow_array(), но и другие DBI-функции. Придётся и для них wrapper'ы писать, типа:

sub dbi_utf8_on_arrayref
{
my $ref = shift;
map {utf8::decode($_) unless utf8::is_utf8($_)} @{$ref};
return $ref;
}

Теперь положим, что мы пишем для web и нам надо вывести HTML-документ. Мы в ВУЗе учились, там нам рассказывали, что отделять логику приложения от оформления результата - это хорошо. Поэтому мы до сих пор используем механизмы шаблонов. Возьмём что-нибудь простенькое, HTML::Template, подключим:

my $tmpl = HTML::Template->new(filename => 'example.html',
die_on_bad_params => 0,
loop_context_vars => 1) || die('Can not create HTML::Template obj');
print($tmpl->output());

..и получим в выводе что-то типа:

Ах, вот как! Оказывается, файл шаблона открывается не как :utf8, а как какой-то :bytes! Можно, конечно, пакет "врукопашную" поправить, но это не наш метод! Можно предварительно открыть файл с шаблоном как :utf8 и передать конструктору file hander, можно потом "перекодировать" результат, непосредственно перед выводом:

my $out = $tmpl->output();
utf8::decode($out);
print($out);

Тогда получим что-то более осмысленное:

Теперь представим, что программа усложнилась и нам её надо отладить. До отладчика тянуться далеко, нам бы просто наглядно посмотреть содержимое переменной. Для этого можно использовать пакет Data::Dumper:

use Data::Dumper;
my $a = 'дададад';
print(Dumper($a), "\n");
^D
$VAR1 = "\x{434}\x{430}\x{434}\x{430}\x{434}\x{430}\x{434}";

Замечательно! Всё правильно, только нечитабельно. Сейчас подхачим этот Dumper:

use Data::Dumper;

$Data::Dumper::Useqq = 1;
{
no warnings 'redefine';
sub Data::Dumper::qquote
{
my $s = shift;
return "'$s'";
}
}

my $a = 'дададад';
print(Dumper($a), "\n");
^D
$VAR1 = 'дададад';

Уфф.. Вот и ладушки!..

...и так с каждым очередным используемым "механизмом" - или приколачиваем туда свои костыли, или ищем ручки управления заранее встроенными туда костылями. Можно "откинуться на спинку кресла" и посмотреть на полученный код - это ж сороконожка и вся на костылях!

Вы всё ещё хотите использовать Perl? =)

программирование, программа, работа, perl, программист, язык

Previous post Next post
Up