Как я могу использовать Perl /// в выражении? - PullRequest
7 голосов
/ 19 апреля 2010

У меня болит голова, глядя на это: Как вы используете s /// в выражении в отличие от присваивания. Чтобы уточнить, что я имею в виду, я ищу perl-эквивалент Python re.sub (...) при использовании в следующем контексте:

newstring = re.sub('ab', 'cd', oldstring)

Единственный способ, которым я знаю, как сделать это в Perl, это:

$oldstring =~ s/ab/cd/;
$newstring = $oldstring;

Обратите внимание на дополнительное задание.

Ответы [ 5 ]

11 голосов
/ 19 апреля 2010

Вы можете использовать ($new = $old) =~ s/whatever/whateverelse/; для точно такой же функции, которую вы ищете:

use strict;
my $old = "OLD";
my $new;
($new = $old) =~ s/OLD/NEW/;
print "old=$old, new=$new";

Производит:

old=OLD, new=NEW

Именно то, что вы хотите

Если вы ищете функцию, вы можете просто определить свою собственную, чтобы избежать назначения:

use strict;
sub re_sub { 
   my ($find, $replace, $old) = @_;
   my $new = $old;
   $new =~ s/$find/$replace/;
   return $new;
}

my $old = "ab";
my $new = re_sub('ab', 'cd', $old);
print "new=$new\n";

Результат: new=cd.

7 голосов
/ 19 апреля 2010

У вас, похоже, неправильное представление о том, как работает =~. =~ - это оператор связывания, который связывает переменную с оператором регулярного выражения. Он не выполняет никаких заданий.

Все операторы регулярного выражения по умолчанию работают с переменной темы $_, поэтому s/foo/bar/; совпадает с $_ =~ s/foo/bar/;. Назначение не происходит. Переменная темы преобразуется.

Случай аналогичен при работе с любой другой переменной. $var =~ s/foo/bar/; преобразует $var, заменяя первый экземпляр foo на bar. Присвоение не происходит.

Лучший совет, который я могу вам дать, это написать Python на Python и Perl на Perl. Не ожидайте, что два языка будут одинаковыми.

Вы можете сделать так, как предлагает DVK, и написать подпрограмму, которая будет воспроизводить привычное для вас поведение замещения.

Или вы можете попробовать какой-нибудь идиоматический Perl. Исходя из вашего желания применить несколько преобразований в одной строке, я привел пару примеров, которые могут оказаться полезными.

Здесь я использую цикл for над одним элементом для актуализации $var и применяю много жестко закодированных преобразований:

for( $var ) {
    s/foo/bar/;
    s/fizz/buzz/;
    s/whop/bop-a-loo-bop/;
    s/parkay/butter/;
    s/cow/burger/;
}

Или, может быть, вам нужно применить переменную группу преобразований. Я определяю подпрограмму для цикла по списку ссылок на массивы, которые определяют старые / новые пары преобразований. В этом примере используется обработка списка аргументов в Perl для обработки любого количества преобразований.

my $foo = transform(
    'abcd' =>
    [ 'a',  'b'    ], 
    [ 'bb', 'c'    ],
    [ 'cc', 'd'    ],
    [ 'dd', 'DONE' ],
);

sub transform {
    my $var = shift;
    for (@_ ) {
        my ($old, $new) = @$_;
        $var =~ s/$old/$new/;
    }

    return $var;
}

Наконец, немного возиться с предоставлением версии преобразования, которая изменяет свой первый аргумент:

my $foo = 'abcd';

transform_in_place(
    $foo =>
    [ 'a',  'b'    ], 
    [ 'bb', 'c'    ],
    [ 'cc', 'd'    ],
    [ 'dd', 'DONE' ],
);

print "$foo\n";

sub transform_in_place {
    for my $i (1..$#_ ) {
        my ($old, $new) = @{$_[$i]};
        $_[0] =~ s/$old/$new/;
    }
}

Для моего собственного проекта я бы, вероятно, использовал один из первых двух вариантов в зависимости от потребностей конкретной проблемы.

7 голосов
/ 19 апреля 2010

Подстановка регулярного выражения в Perl всегда происходит «на месте». Поэтому вам нужно скопировать строку в новую переменную и работать с новой переменной:

(my $newstring = $oldstring) =~ s/ab/cd/;
2 голосов
/ 19 апреля 2010

Вы хотите, чтобы $ newstring был результатом подстановки, верно?

Примерно так:

($newstring = $oldstring) =~ s/ab/cd;

Должно работать. Присвоение устанавливает $newstring в $oldstring и затем оценивается в $newstring, на что действует подстановка.

1 голос
/ 19 апреля 2010

Исходя из этого, могу ли я считать, что у вас не может быть двух s /// в одной строке, одна из которых использует результат другой, без промежуточных присваиваний? - mikeY

Да, вы правы. Если вы хотите применить несколько замен к одной и той же строке, я бы сделал

    $newstring = $oldstring ;
    $newstring  =~ s/ab/cd/ ;
    $newstring  =~ s/xx/yy/ ;

Следующее не будет работать, потому что s// возвращает количество сделанных замен, а не измененную строку.

    $newstring = $oldstring) =~ s/ab/cd/ =~ s/xx/yy/ ;

Итак, операции с регулярным выражением в Perl сильно отличаются от операций с Python, и вы лучше пытаетесь узнать, что делает Perl с нуля, чем пытаться отобразить концепции Python на Perl

...