Расширение переменных во входных данных

Проблема

Имеется строка, внутри которой присутствует ссылка на переменную: You owe $debt to me.
Требуется заменить имя переменной $debt в строке ее текущим значением.

Решение

Если все переменные являются глобальными, воспользуйтесь подстановкой с символическими ссылками:
$text =~ s/\$(\w+)/${$1}/g;
Но если среди переменных могут встречаться лексические ( ) переменные, следует использовать /ее:
$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



2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: