С помощью tr///
я могу сделать это:
my $str = 'xABCz';
$str ~~ tr:c/ABC//;
say "-->{$str}<--";
--output:--
-->ABC<--
Но с помощью TR///
, который создает новую строку, похоже, нет способа применить его непосредственно к строке:
my $str = 'xABCz';
$str ~~ tr:c/ABC//;
my $new_str = $str ~~ TR:c:d/ABC//;
say "-->{$new_str}<--";
--output:--
-->True<--
Я могу использовать with
, чтобы установить $_
на $str
:
my $str = 'xABCz';
with $str { # now $_ refers to $str
my $new_str = TR:c:d/ABC//; # TR/// is called on $_.
say "-->{$new_str}<--";
}
--output:--
-->ABC<--
...или даже:
my $str = 'xABCz';
my $new_str = TR:c:d/ABC// with $str;
say "-->{$new_str}<--";
--output:--
-->ABC<--
В Perl я бы написал:
my $str = 'xABCz';
my $new_str = $str =~ tr/ABC//rcd; #r - new_string, c - complement, d - delete
say $new_str;
-output:--
ABC
К вашему сведению, вы можете перезаписать оригинал $str
с помощью: $str = TR:c:d/ABC// given $str;
.
Str.trans должен иметь такой же эффект неразрушающим образом.
my $new_str = $str.trans("ABC" => "")
...так что в моем случае: $new_str = $str.trans('ABC' => '', :c, :d);
На самом деле, в этом случае :d
не нужен из-за того, что trans() повторяет символы замены, если в совпадении больше символов. Например: 'ABCDE'.trans('ABCD' => 'xy')
выходы xyxyE
. С другой стороны, добавление опции :d приведет к удалению всех символов совпадения, для которых нет соответствующего символа замены: 'ABCDE'.trans('ABCD' => 'xy', :d)
выводит xyE
.
Не существует правильного способа использования TR
с ~~
; TR
всегда должен работать с переменной темы (например, устанавливаться с помощью with
). TR
— это транслитерационный эквивалент S
(неразрушающая замена), а в документации для S отмечается, что:
Примечание. Поскольку результат получается как возвращаемое значение, использование этого оператора с оператором
~~
smartmatch является ошибкой и приведет к выдаче предупреждения. Чтобы выполнить замену переменной, которая не является той$_
, которую использует этот оператор, присвойте ей псевдоним$_
с помощьюgiven
,with
или любым другим способом. Альтернативно используйте метод.subst
.
Точно так же использование TR
с ~~
является ошибкой (и, как отметил выше @raiph, , вероятно, должен выдать предупреждение ). Вместо этого вам следует установить $_
с помощью given
/etc или использовать метод .trans
.
Не уверен, есть ли у меня «практическое правило» на этот счет, но можно рассмотреть возможность использования s///
и tr///
только с sed
-подобными -pe
флагами командной строки (и/или ~~
смарт-сопоставителем, как показано в ОП) . Во всех остальных случаях используйте S///
и TR///
, задав тему (например, с помощью given
) при необходимости:
#Below works:
~$ raku -pe 's:g/\,/\t/;' file.csv
#OR
~$ raku -pe 'tr/,/\t/;' file.csv
Что сбивает с толку, так это то, что sed
, как «редактор потока», выбирает значение из потока, изменяет его и помещает («возвращает») значение обратно в поток для вас. Коротко и понятно, но сильно отличается от awk
или практически от любого другого динамичного языка, с которым вы можете играть.
Чтобы выполнить ту же задачу с awk
и многими другими языками, вам понадобится явный оператор output
с изменяемыми строками. Вот где действительно блестят обозначения «big-S» и «big-TR» (обратите внимание на -ne
неавтопечатающие, awk
-подобные флаги командной строки):
#Below works:
~$ raku -ne 'S:g/\,/\t/.put;' file.csv
#OR
~$ raku -ne 'TR/,/\t/.put;' file.csv
Так что это может показаться странным, если вы не пишете однострочники, но вы можете просто запомнить из вышесказанного: чтение lines()
из файла потребует нотаций «big-S» или «big-TR», как во втором (awk
- подобный случай), в отличие от первого случая, подобного sed
:
#Below with tr/// doesn't work:
~$ raku -e 'for lines() {tr/,/\t/.put};' file.csv > file.tsv
Cannot modify an immutable Str (input,file,text,here...)
in block <unit> at -e line 1
#Below with TR/// works as desired:
~$ raku -e 'for lines() {TR/,/\t/.put};' file.csv > file.tsv
(Наконец, вы должны знать, что Raku покончил с -i
редактированием файлов «на месте». У меня есть только неофициальные доказательства следующих рассуждений, но некоторые комментарии SO предполагают, что конечные пользователи Perl случайно «очищали» свои входные данные. файлы с неправильной комбинацией флагов командной строки и операторов «small-s» или «small-tr», отсюда и введение нотаций «big-S» или «big-TR», которые по своей сути более безопасны).
К вашему сведению, этот комментарий @BradGilbert предполагает, что S///
является заменой Perl s///r
на Raku: nntp.perl.org/group/perl.perl6.users/2019/06/msg6777.html
см. выпуск ракудо №1551.