Модификатор Perl Regex 'e' (eval) с s///

У меня возникли небольшие проблемы с пониманием этого простого использования модификатора регулярного выражения /e.

my $var = 'testing';
$_ = 'In this string we are $var the "e" modifier.';

s/(\$\w+)/$1/ee;

print;

Возвращает: «В этой строке мы тестируем модификатор «e».

Я не понимаю, почему требуются два модификатора «e». Насколько я понимаю, $1 должен захватить "$var" из строки, а затем один модификатор "e" должен иметь возможность заменить переменную ее значением. Однако я, должно быть, что-то неправильно понимаю, поскольку попытка выполнения приведенного выше кода только с одним модификатором «e» явно не заменяет ничего в строке.

Извините, что задаю такой простой вопрос!

Спасибо.


person pb149    schedule 21.05.2011    source источник
comment
обратите внимание, что e не является модификатором регулярного выражения, поскольку оно не влияет на регулярное выражение! Это влияет только на заменяемую деталь. Таким образом, e изменяет оператор s///, а не регулярное выражение.   -  person tadmc    schedule 21.05.2011


Ответы (3)


Это не совсем «простой» вопрос, так что не корите себя.

Проблема в том, что с одним /e RHS понимается как код, чей результат eval используется для замены.

Что это за РХС? Это $1. Если вы оценили $1, вы обнаружите, что содержит строку $var. Он не содержит содержимого указанной переменной, просто $, за которым следует v, за которым следует a, за которым следует r.

Поэтому вы должны вычислить его дважды: один раз, чтобы превратить $1 в $var, а затем еще раз, чтобы превратить предыдущий результат $var в строку "testing". Это можно сделать с помощью модификатора double ee в операторе s. .

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

use v5.10;

our $str = q(In this string we are $var the "e" modifier.);
our $var = q(testing);

V1: {
    local $_ = $str; 
    s/(\$\w+)/$1/e;
    say "version 1: ", $_;

}

V2: {
    local $_ = $str;
    s/(\$\w+)/$1/ee;
    say "version 2: ", $_;
}

V3: {
    no strict "refs";
    local $_ = $str;
    s/\$(\w+)/$$1/e;
    say "version 3: ", $_;
}

При запуске это производит:

version 1: In this string we are $var the "e" modifier.
version 2: In this string we are testing the "e" modifier.
version 3: In this string we are testing the "e" modifier.
person tchrist    schedule 21.05.2011
comment
Это здорово, спасибо. Любопытно, почему создание регулярного выражения s/(\$\w+)/$1/ с модификатором NO по-прежнему заменяет его захваченным значением ($var)? Мне кажется, для этого и нужен первый /e? - person pb149; 21.05.2011
comment
@ user761513: Без модификатора $1 в качестве замещающего текста используется как строка. С одним e оно используется как выражение с точно таким же результатом. Чтобы увидеть разницу, сравните s/…/$1 (hello)/ (строку) с s/…/uc($1)/e (выражением). - person Gilles 'SO- stop being evil'; 21.05.2011
comment
В частности, без модификатора замещающий текст действует как строка двойных кавычек. Следовательно, $1 интерполирует то, что было захвачено первым набором скобок. - person pjf; 21.05.2011

Чтобы было ясно, форма s//ee вообще не изменяет ваш шаблон регулярного выражения или интерпретацию регулярного выражения. Это необязательная обработка замещающей боковой строки после выполнения регулярного выражения. (См. операторы PERLOP, подобные кавычкам)

e или ee просто смешиваются с параметрами регулярного выражения на стороне PATTERN в форме s/PATTERN/REPLACEMENT/msixpodualgcer.

От Перлопа:

Опции аналогичны m// с добавлением следующих специальных опций замены:

e Evaluate the right side as an expression.
ee  Evaluate the right side as a string then eval the result.
r   Return substitution and leave the original string untouched.

Вы можете увидеть такое же поведение типов e и ee в ситуациях без регулярных выражений, как показано в этом примере:

#!/usr/bin/perl 
use warnings;
use strict;

my $var = "var's contents";
my $str='"-> $var <-"';
print eval('$str'), "\n";        # equivalent to s//e
print eval(eval('$str')), "\n";  # equivalent to s//ee

Вывод:

"-> $var <-"
-> var's contents <-
person the wolf    schedule 21.05.2011
comment
Что делает # use strinct? ;-} - person dawg; 21.05.2011
comment
[Отклонено как редактирование] Последнее замечание, просто для полноты картины: вы можете добавить еще больше e, это не выполнимо не потому, что документация на этом останавливается: my $testing = 'Phew!'; мой $ var = '$ тестирование'; $_ = 'Мы $var модификатор e.'; с/(\$\w+)/$1/e; Распечатать; $_ = 'Мы $var модификатор e.'; с/(\$\w+)/$1/ee; Распечатать; $_ = 'Мы $var модификатор e.'; с/(\$\w+)/$1/ееее; Распечатать; производя мы $var e модификатор. Мы тестируем модификатор $e. Мы Фу! модификатор е. - person OmarOthman; 03.08.2015
comment
@thewolf Не могли бы вы отредактировать свой пост с моей модификацией? - person OmarOthman; 11.08.2015

Попробуйте утилиту переименования из последнего пакета Perl с:

rename -v 's/\b(\w)/uc($1)/eg' *

Здесь шаблон \b находит границу слова, а модификатор e включает оценку при замене, а g заменяет все вхождения.

Вы также можете переименовать в camelCase с помощью:

rename -v 's/\b(\w)/uc($1)/eg' *
rename -v 's/^(\w)/lc($1)/e' *
rename -v 's/\s+//g' *
person Xiè Jìléi    schedule 02.06.2015