Ефективност на разделяне на много дълга транслитерация в Perl

Имам тази много дълга транслитерация:

$text =~ tr/áàăâǎåǻäǟãȧǡąāȁȃɑʙƀɓƃćĉčċçȼƈɕʗďđðɖɗƌȡéèĕêěëėȩęēȅȇɇɛ/aaaaaaaaaaaaaaaaabbbbcccccccccdddddddeeeee/;
# Etc. (About 400 chars)

Искам да го разделя на няколко транслитерации, тъй като полученият код би бил по-лесен за поддръжка:

$text =~ tr/áàăâǎåǻäǟãȧǡąāȁȃɑ/aaaaaaaaaaaaaaaaa/;
$text =~ tr/ʙƀɓƃ/bbbb/;
$text =~ tr/ćĉčċçȼƈɕʗ/ccccccccc/;
# Etc.

Вярвам, че това ще забави нещата, но бих искал да знам със сигурност. Този процес се изпълнява около 1000 пъти в секунда на доста натоварен сървър.

Благодаря.


person calvillo    schedule 06.11.2013    source източник
comment
tr и regex са две различни неща. tr просто превежда знаци, така че няма причина по-дългият да е по-бавен от късия.   -  person acfrancis    schedule 06.11.2013
comment
няколко пъти в секунда? използвайте Benchmark, за да измерите времето, което действително отнема, след което решете дали изобщо си струва да помислите.   -  person ysth    schedule 06.11.2013
comment
Съжалявам за това. Току що редактирах въпроса. Терминологията беше грешна и не бях много наясно с целите си.   -  person calvillo    schedule 06.11.2013


Отговори (3)


Ето бенчмарк:

use Benchmark qw(:all);

my $str = 'áàăâǎåǻäǟãȧǡąāȁȃɑʙƀɓƃćĉčċçȼƈɕʗďđðɖɗƌȡéèĕêěëėȩęēȅȇɇɛ/aaaaaaaaaaaaaaaaabbbbcccccccccdddddddeeeee';
my $count = -2;
cmpthese($count, {
    'one tr' => sub {
        $str =~ tr/áàăâǎåǻäǟãȧǡąāȁȃɑʙƀɓƃćĉčċçȼƈɕʗďđðɖɗƌȡéèĕêěëėȩęēȅȇɇɛ/aaaaaaaaaaaaaaaaabbbbcccccccccdddddddeeeee/;
    },
    'multi tr' => sub {
        $str =~ tr/áàăâǎåǻäǟãȧǡąāȁȃɑ/aaaaaaaaaaaaaaaaa/;
        $str =~ tr/ʙƀɓƃ/bbbb/;
        $str =~ tr/ćĉčċçȼƈɕʗ/ccccccccc/;
        $str =~ tr/ďđðɖɗƌȡ/ddddddd/;
        $str =~ tr/éèĕêěëėȩęēȅȇɇɛ/eeeee/;
    },
});

резултат:

              Rate multi tr   one tr
multi tr 1215538/s       --     -81%
one tr   6271883/s     416%       --

Както виждаме, един tr е 5 пъти по-бърз от multi-tr.

person Toto    schedule 06.11.2013

Можете да създадете транслитератор:

my %translits = (
   'áàăâǎåǻäǟãȧǡąāȁȃɑ' => 'a',
   'ʙƀɓƃ'              => 'b',
   'ćĉčċçȼƈɕʗ'         => 'c',
);

my $pat  = '';
my $repl = '';
for (keys(%translit)) {
   $pat  .= $_;
   $repl .= $translit{$_} x length($_);
}

my $tr1 = eval "sub { tr/\Q$pat\E/\Q$repl\E/ }" or die $@;
   -or-
my $tr2 = eval "sub { \$_[0] =~ tr/\Q$pat\E/\Q$repl\E/ }" or die $@;

След това го използвайте така:

$tr1->() for $str;
   -or-
$tr2->($str);

Разбира се, винаги можете да използвате Text::Unidecode.

person ikegami    schedule 06.11.2013
comment
Вашият код е много умен. Решава проблема с поддръжката, който имам, благодаря ви много. Ще трябва обаче да приема последния отговор, тъй като той отговаря на въпроса по-директно. Относно Text::Unicode, опитах го, но работи по мистериозен начин и вярата ми е слаба тези дни. - person calvillo; 06.11.2013

Бих очаквал второто решение с три операции да бъде по-бавно, защото сканира повторно символи в $text, които вече са били заменени.

person user2719058    schedule 06.11.2013
comment
Това е добра точка. Всеки отделен tr трябва да е с еднаква скорост, независимо колко знака има в него. Но пускането му повече от веднъж трябва да е по-бавно. - person acfrancis; 06.11.2013
comment
@acfrancis: Какво те кара да мислиш, че дължината на набора за превод и типът на елементите му нямат значение? Всеки входен знак трябва да бъде проверен спрямо всеки знак или клас знаци в набора за превод, така че бих очаквал размерът на последния и типът на неговите елементи да имат значение. - person user2719058; 06.11.2013
comment
Да добавя, че мисля за общия случай; с фиксирани знаци в набора за превод хешът може да даде постоянна скорост, но с класове знаци не виждам как. И дори с хеш, по-големият хеш се нуждае от повече изчислителна мощност, за да настрои... - person user2719058; 06.11.2013
comment
В разумни граници бих очаквал Perl да имплементира tr с нещо като хеш-таблица (всеки символ отляво е ключ, а съответният знак отдясно е стойността), която има достъп до всеки отделен ключ в O(1), независимо от броя на ключовете. Ако сте имали патологично tr с милиони знаци, това може да не е вярно, но за ежедневна употреба се обзалагам, че е така. - person acfrancis; 06.11.2013
comment
Пропуснах този втори коментар, преди да отговоря. Разрешени ли са класове символи в tr? Мислех, че не са, но може и да греша. Така или иначе, по-голямата цена за настройка се заплаща по време на компилиране, а не на изпълнение. - person acfrancis; 06.11.2013
comment
Уф, обърках tr на perl с tr(1), съжалявам за това. - person user2719058; 06.11.2013
comment
Ако входните и изходните набори не бяха различни, разделянето на tr може дори да промени семантиката по погрешка. Изглежда, че това не е така за calvillo, но всеки друг, който чете този въпрос, трябва да внимава :) - person hobbs; 06.11.2013
comment
Изглежда, че user2719058 е бил прав. Тествах приетия отговор с извадка от действителните данни, които обработвам, и резултатите са последователни: той се увеличава със 100% за всяка нова транслитерация. Ще пробвам решението на ikegami. - person calvillo; 06.11.2013