Pull to refresh

Транслитерация в Perl6

Reading time 2 min
Views 2.8K
Original author: carl
«Транслитерация» означает замену символов. Именно этим и занимается метод Str.trans

say "GATTACA".trans( "TCAG" => "0123" );  # выводит "3200212\n"


Люди, знакомые с Perl 5 или с оболочкой Unix распознают в этом tr/tcag/0123/, а для остальных поясним: каждая буква T заменяется на 0, каждая C на 1, и так далее. Две строки, TCAG и 0123, предоставляют алфавиты, которые надо взаимозаменять.

Это можно использовать для скорости при реализации разных операций. Например, простая функция, «шифрующая» текст методом ROT-13 (замена символа тем, что стоит через 13 позиций от него):

sub rot13($text) { $text.trans( "A..Za..z" => "N..ZA..Mn..za..m" ) }


.trans раскрывает диапазоны…, поэтому «n..z» будет означать «nopqrstuvwxyz». Таким образом, функция rot13 заменит конкретные части алфавита ASCII другими частями.

В Perl 5 вместо двух точек… используется тире — , но в Perl 6 мы решили, что две точки лучше обозначают концепцию «промежутка» – в языке, в регулярках и в транслитерации.

Метод .trans не меняет $text, а только возвращает новое значение. Так принято в Perl 6 – мы предлагаем методы без побочных эффектов. Но при необходимости подобное поведение можно определить через .=:

$kabbala.=trans("A..Ia..i" => "1..91..9");


Это работает и для всех остальных методов. Программистам всё же рекомендуется писать библиотеки, поддерживающие первый метод, и тогда наш мир будет светлее и лучше.

Но это не был бы Perl 6, не содержи .trans скрытой силы, превышающей простое tr///. Вот что он ещё делает.

Допустим, нам надо экранировать некоторые символы для HTML, то есть заменить их согласно списку:

    & => &
    < => <
    > => >


Можно ограничиться регулярками. Но может так получится, что вы на этом шаге застрянете в бесконечном цикле (& => & => &amp; => ...). Но проблема даже не в этом, а в том, что вы будете заниматься сшиванием кусков строк, вместо того, чтобы охватить задачу целиком на более высоком уровне. Кроме того, хотелось бы, чтобы метод работал примерно так:

  маска => вещь
  маскарад => мероприятие


Если сначала будет выполняться первая замена, то на долю второй ничего не останется – и результат будет неправильным. Обычно нам надо менять более длинные строки в первую очередь.

И такое поведение даёт нам .trans в Perl 6. Это его скрытое оружие – передача пары массивов, а не просто пары строк. Для экранирования символов нужно всего лишь указать:

my $escaped = $html.trans(
    [ '&',     '<',    '>'    ] =>
    [ '&amp;', '&lt;', '&gt;' ]
);


и все эти нетривиальные, но нудные задачи по замене символов в правильном порядке без выпадания в вечный цикл будут решены за нас.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+6
Comments 3
Comments Comments 3

Articles