Расширение переменных во входных данных
Проблема
Имеется строка, внутри которой присутствует ссылка на переменную: You owe $debt to me.
Требуется заменить имя переменной $debt в строке ее текущим значением.
Решение
Если все переменные являются глобальными, воспользуйтесь подстановкой с символическими ссылками:
$text =~ s/\$(\w+)/${$1}/g;
Но если среди переменных могут встречаться лексические (
mу) переменные, следует использовать /ее:
$text =~ s/(\$\w+)/$1/gee;
Комментарий
Первый способ фактически сводится к следующему: мы ищем нечто похожее на имя переменной, а затем
интерполируем ее значение посредством символического разыменования (dereferencing). Если $1 содержит
строку somevar, то ${$1} будет равно содержимому $somevar. Такой вариант не будет работать при
действующей директиве use strict 'refs',
потому что она запрещает символическое разыменование.
Приведем пример:
use vars qw($rows $cols);
no strict 'refs'; # для приведенного ниже ${$1}
my $text;
($rows, $cols) = (24, 80);
$text = q(I am $rows high and $cols long); # апострофы!
$text =~ s/\$(\w+)/${$1}/g;
print $text;
1 am 24 high and 80 long
Возможно, вам уже приходилось видеть, как модификатор подстановки /е используется для вычисления
заменяющего выражения, а не строки. Допустим, вам потребовалось удвоить каждое целое число в строке:
$text = "I am 17 years old";
$text =~ s/(\d+)/2 * $1/eg;
Перед запуском программы, встречая /е при подстановке, Perl компилирует код заменяющего выражения вместе с
остальной программой, задолго до фактической подстановки. При выполнении подстановки $1 заменяется
найденной строкой. В нашем примере будет вычислено следующее выражение:
2 * 17
Но если попытаться выполнить следующий фрагмент:
$text = 'I am $AGE years old'; # Обратите внимание на апострофы!
$text =~ s/(\$\w+)/$1/eg; # НЕВЕРНО
при условии, что $text содержит имя переменной $AGE, Perl послушно заменит $1 на $AGE и вычислит следующее выражение:
'$AGE'
В результате мы возвращаемся к исходной строке. Чтобы получить значение переменной, необходимо снова
вычислить результат. Для этого в строку добавляется еще один модификатор /е:
$text =~ s/(\$\w+)/$1/eeg; # Находит переменные mу()
Да, количество модификаторов /е может быть любым. Только первый модификатор компилируется вместе с
программой и проверяется на правильность синтаксиса. В результате он работает аналогично конструкции
eval {BLOCK}, хотя и не перехватывает исключений. Возможно, лучше провести аналогию с
do {BLOCK}.
Остальные модификаторы /е ведут себя иначе и больше напоминают конструкцию
eval "STRING". Они не
компилируются до выполнения программы. Маленькое преимущество этой схемы заключается в том, что вам
не придется вставлять в блок директиву no strict 'refs'. Есть и другое огромное преимущество:
этот механизм позволяет находить лексические переменные, созданные с помощью ту, — символическое
разыменование на это не способно.
В следующем примере модификатор /х разрешает пропуски и комментарии в шаблоне подстановки, а
модификатор /е вычисляет правостороннее выражение на программном уровне. Модификатор /е позволяет
лучше управлять обработкой ошибок или других экстренных ситуаций:
# Расширить переменные в $text. Если переменная не определена,
# вставить сообщение об ошибке.
$text =~ s{
\$ # Найти знак доллара
(\w+) # Найти "слово" и сохранить его в $1
}{
no strict 'refs';
if (defined $$1) {
$$1; # Расширять только глобальные переменные
} else {
"[NO VARIABLE: \$$1]"; # Сообщение об ошибке
}
}egx;
Обратите внимание на изменение синтаксиса $$1 в Perl 5.004; когда-то это выражение означало ${$}1, а
теперь оно означает ${$1}. Для обеспечения обратной совместимости в строках оно сохраняет старый смысл
(но выдает предупреждение с -w). Запись ${$1} используется в строках для того, чтобы предотвратить разыменование PID.
Если значение $$ равно 23448, то $$1 в строке превращается в 234481, а не в значение переменной, имя которой хранится в $1.
См. такжеОписание оператора
s/// и функции
eval
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|