Что действует оператор замещения Perl?

Я программировал в Perl, в течение многих лет, но только спорадически это мой основной язык. Поскольку я часто бываю месяцами без написания perl, я сильно полагаюсь на свою собачью книгу верблюдов, чтобы напомнить мне, как делать что-то. Однако, когда я копирую рецепты дословно без понимания, это беспокоит меня. Это одно из самых неприятных: на странице 154 3-го издания Camel есть пример для "модификации строк en passant, который читается следующим образом:

($lotr = $hobbit) =~ s/Bilbo/Frodo/g;

Q1), что здесь происходит? На чем, собственно, работает регулярное выражение?

Q2) Этот сверхмагический синтаксис необходим для такой базовой операции, как "взять строку из $a, изменить ее с помощью регулярного выражения, поместить результат в $b"?

Q3) Как выполнить эту операцию с использованием переменной по умолчанию цикла в качестве начальной строки?

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

Ответы

Ответ 1

Хммм... ($lotr=$hobbit) =~ s/Bilbo/Frodo/g является одним из многих магов Perl. Теперь для некоторых ответов.

Q1) $lotr присваивается значение, содержащееся в $hobbit. После назначения мы можем забыть об исходной переменной. Относитесь к ($lotr = $hobbit) как к собственному утверждению как-если бы мы написали:

$lotr = $hobbit;
$lotr =~ s/Bilbo/Frodo/g;

вместо этого. Регулярное выражение работает на $lotr.

Q2) Синтаксис - это просто однострочная версия приведенного выше фрагмента. Подумайте об этом как "скопируйте строку из $a, скопируйте ее в $b и измените $b с помощью регулярного выражения" вместо "возьмите строку из $a, измените ее с помощью регулярного выражения, поместите результат в $b"

Q3) Я предполагаю, что вы имеете в виду пространство поиска шаблона по умолчанию с помощью "переменной по умолчанию цикла"? В этом случае просто используйте $_ вместо $hobbit:

while (<>) {
  chomp;
  ($lotr = $_) =~ s/Bilbo/Frodo/g;
  print "\$lotr = [$lotr]\n";
  print "\$_    = [$_]\n";
}

Интересно, что волшебная переменная var $_ не изменяется этой операцией. Вот как вы можете заключить, что назначение происходит до подстановки регулярных выражений и что подстановка никак не взаимодействует в пространстве шаблонов по умолчанию.

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

Ответ 2

Различные языки выполняют разные операции с оператором присваивания. В некоторых это выражение, а не выражение, поэтому не может быть объединено в более крупное выражение. В некоторых случаях он возвращает назначенное значение, но только как значение (часто называемое rvalue), а не как то, что может быть изменено или назначено (lvalue). Примером этого является C, где вы может написать:

 a = b = c;  # assign value of c to b and a

но не:

 ++(b = a);  # assign value of a to b, then increment b

И в некоторых случаях результатом присваивания присваивается значение lvalue. (В Perl это относится только к скалярным присваиваниям, назначение списков - более сложный зверь.) Таким образом, вы можете делать ++ ($ b = $a) или ($ b = $a) = ~ s/a/b/или любая другая операция, которая ожидает lvalue при назначении, и сначала выполнит назначение, а затем дополнительно изменит значение lvalue, присвоенное.

Ответ 3

Если в Q2 вы хотите взять подстроку из $a, вы можете найти эту идиому полезной:

($b) = $a =~ /(substring-to-match)/;
$b =~ s/regex-on-susbtring/result-string/;

Также обратите внимание, что $a и $b не являются нормальными переменными в Perl, поскольку у них есть специальные правила области, связанные с функцией сортировки. Подробнее см. "Perldoc perlvar".