32
1 1 Unicode в Perl и как перевести на него систему Виктор Ефимов

виктор ефимов «Unicode в perl и как перевести на него систему» (yapc russia 2014, спб)

Embed Size (px)

Citation preview

11

Unicode в Perl и как перевести на него систему

Виктор Ефимов

2

Перейти с CP1251 на Unicode.В Web приложении на Perl

Сотни тысяч строк Perl кода

Сайт, бэкофис, много скриптов

Регистрация IDN доменов на разных языках.

Чтобы работать с текстом на разных языках одновременно.

to unicode or not to unicode

3

Чтобы работать с текстом на разных языках одновременно.

to unicode or not to unicode

Даже для одного языка - однобайтные кодировки - не вариант

4

use Modern::Perl;print "YES\n" if "\x85" =~ /^\s+$/;__END__YES

to unicode or not to unicode

lc(), uc(), \w \W \s \S и т.д. могут не работать

5

\x85 в cp1251 это

Текстовые строкиВнутренний

форматКак интерпретируются Как

интерпретируется 0xD0 0xAF

С флагом UTF-8

(Unicode)

Строка считается последовательностью

unicode символов, закодированных в UTF-8

Один символ "Я" (unicode U+042F)

Без флага UTF-8

Каждый байт - один символ

Два символа с кодами (U+00D0 U+00AF )

6

Сделать так чтобы один и тот код работал со строками в разных форматах (unicode или cp1251)

Работаем одновременно в разных кодировках

В зависимости от конфига, приложение сможет работать то в одной кодировке то в другой

7

"Старый" код будет совместим только с режимом работы в формате cp1251

sub func {my ($s) = @_; # $s либо cp1251 либо unicodeto_unicode($s); # теперь $s - точно unicode$s =~ s/(\W+)/_/g; # текстовая операцияfrom_unicode($s); # $s в том формате что и былоreturn $s;

}

Работаем одновременно в разных кодировках

8

Как выглядит такой код

sub func {my ($s) = @_; # $s либо cp1251 либо unicode$s = Encode::decode("CP1251", $s); # to_unicode($s)$s =~ s/(\W+)/_/g; # текстовая операция$s = Encode::encode("CP1251", $s); # from_unicode($s)return $s;

}

Работаем одновременно в разных кодировках

9

Как этот код работает в режиме CP1251

sub func {my ($s) = @_; # $s либо cp1251 либо unicode

# to_unicode($s) - ничего не делает!$s =~ s/(\W+)/_/g; # текстовая операция

# from_unicode($s) - ничего не делает!return $s;

}

Работаем одновременно в разных кодировках

10

Как этот код работает в режиме Unicode

Работаем одновременно в разных кодировках

11

Режим to_unicode from_unicode

CP1251 CP1251 -> UNICODE

UNICODE -> CP1251

Unicode NOP NOP

Работаем одновременно в разных кодировках

12

Режим to_unicode from_unicode to_cp1251 from_cp1251

CP1251 CP1251 -> UNICODE

UNICODE -> CP1251

NOP NOP

Unicode NOP NOP UNICODE -> CP1251

CP1251 -> UNICODE

$value =~ /Привет/i # исходник в CP1251

Что ещё нужно сделать с кодом

13

Строковые константы

use utf8;$value =~ /Привет/i; # исходник в UTF-8

Было

Стало

Что ещё нужно сделать с кодом

14

Расширенное толкование метасимволов регэкспов

Теперь это тоже \d

Что ещё нужно сделать с кодом

15

Ввод-вывод

to_unicode($str);open my $fh, ">:encoding(UTF-8)", $filename;print $fh $str;

Тестирование

16

package MyClass;use utf8;sub myfunc {

my ($x, $data) = @_;do_something($data);if ($x == 42) {

do_even_more($data);$s =~ s/Ё/Е/g;

}}

Тестирование

17

package MyClass;use utf8;sub myfunc {

my ($x, $data) = @_;do_something($data);if ($x == 42) { # Always TRUE

do_even_more($data);$s =~ s/Ё/Е/g;

}}

Test::Spec

18

Тестирование

Test::Spec::Mocks

$myobj->expects('do_something')->with("Привет")->returns("Тест");

MyApp->config( encoding => 'UTF-8' )

19

Catalyst

Content-Type: text/html; charset=utf-8

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Перекодировать шаблоны

20

Template Toolkit

my $provider = Template->new({ ENCODING => 'utf8',});

SET NAMES 'cp1251' SET NAMES 'utf8'

21

DBI, DBD::mysql

Только байты. Никакого текста.

22

Redis, Redis::Fast

Perl не может отличить байты от текста

Используем сериализацию. Например Storable.только сериализация которая восстанавливает все скаляры в оригинальном виде

Почта

23

Другие большие подсистемы

Логи

Что-то ещё.. Индивидуальный подход к каждой.

sha256("привет") - не определено!

24

Пароли

sha256(utf8("привет")) <> sha256(cp1251("привет"))

Бизнес-логика - потом

25

Бизнес-логика

Проверяем что входные данные - валидируются

26

Сложные структуры данныхmy $dataref = +{

x => [1,2,3,"тест"],y => { a => 42 },

};to_unicode_recursive($dataref);

27

Сложные структуры данных

sub myfunc {my ($str) = @_;to_unicode_recursive $str; # в unicode$is_greetings = $str->{field} =~ /Привет/i;die if rand() > 0.5; # проблемаfrom_unicode_recursive $str; # обратноreturn $is_greetings;

}

28

Сложные структуры данных

sub myfunc {my ($str) = @_;my $str_u = to_unicode_clone $str; # в unicodemy $is_greetings = $str_u->{field} =~ /Привет/i;die if rand() > 0.5; # нет проблем!# обратно перекодировать не нужноreturn $is_greetings;

}

29

Сложные структуры данныхmy $dataref = +{

x => [1,2,3,"тест"],y => { a => 42 },z => bless { field => "привет"}, 'MyObject'

};to_unicode_recursive($dataref); # ошибка

30

Запуск на productionModule1.pm (unicode ok)

Module2.pm (unicode ok)

Module3.pm (unicode ok)

Module4.pm (legacy)

script1.pl

script2.pl

ps#2618 unicode

ps#2621 unicode

ps#2622 CP1251

ps#2626 CP1251

ps#2624 CP1251

В общем Redis сервере кэшируются фрагменты html в разных кодировках

31

Запуск на production

Веб приложение пишет в базу символы, которых нет в cp1251, значит cp1251 процессы их “не увидят”

Написание возможно в 2 строкиПлашку регулировать по длине текста

Вывод или посыл зрителюСпасибо!Буду рад ответитьна ваши вопросы!

E-mail:[email protected]

32