Forum Webscript.Ru
Программирование => Perl => Тема начата: SPEED от 26 Ноября 2006, 00:02:56
-
Есть код:
my $shablon = qq{text %%shablon_text%% text};
my $shablon_text = "замена шаблона";
my $text_shablon = $shablon;
$text_shablon =~ s/%%(.*?)%%/${$1}/ig;
print $text_shablon;
При таком раскладе в переменной $shablon не происходит замены %%shablon_text%% на нужное значение.
Если убрать my у переменной $shablon_text то все работает, но необходимо объявить переменную как my в рамках функции.
Почему не работает с my? И как быть?
-
#!/usr/bin/perl
use strict;
repl();
sub repl
{
my $shablon = qq{text %%shablon_text%% text};
my $shablon_text = "замена шаблона";
my $text_shablon = $shablon;
my %templates = (\'shablon_text\' => $shablon_text,
\'la\' => \'lallaalal\');
$text_shablon =~ s/%%(.*?)%%/$templates{$1}/g;
print $text_shablon;
}
-
Такой вариант был.
Однако, допустим мы не знаем какие переменные есть в шаблоне, которые надо заменять.
В таком случае нам надо дополнительно обрабатывать шаблон на получение хеша всех переменных которые там есть. Правильно?
Дополнительная обработка шаблона - это дополнительное время генерации скрипта.
А есть какие-то варианты без хеша?
И попутный вопрос. Если бы не было use strict то можно использовать local - локальное определение переменной (в рамках функции), но strict не дает использоать local.
Есть еще какие нибудь варианты?
-
Если говорить о примере с хешем:
my $shablon = qq{text %%shablon_text%% %%shablon_text1%% %%shablon_text2%% text};
my $shablon_text = "замена шаблона";
my $shablon_text1 = "замена шаблона1";
my $shablon_text2 = "замена шаблона2";
my %shablon_text;
while($shablon =~ /%%(.*?)%%/ig)
{
$shablon_text{$1} = ${$1};
}
my $text_shablon = $shablon;
$text_shablon =~ s/%%(.*?)%%/$shablon_text{$1}/ig;
print $text_shablon;
Но опять же ${$1} внутри while не заменяется на нужную переменную.
-
при такой записи это воспринимается как символическая ссылка, а символические ссылки обрабатываются с помощью таблицы имен пакета. Так что не получится через локальную в рамках функции ;) если только вынести функцию в отдельный пакет, и там сделать переменные глобальными.
-
можно конечно и так сделать
$text_shablon =~ s/%%(\\w+)%%/\'$\'.$1/gee;
но это весьма неразумно
-
Привет.
Лексических переменных my нет в таблице имен. Наверно, поэтому без /ee не работает.
===
Perl Cookbook
1.8. Расширение переменных во входных данных
*** Проблема ***
Имеется строка, внутри которой присутствует ссылка на переменную:
You owe $debt to me.
Требуется заменить имя переменной $debt в строке её текущим значением.
*** Решение ***
Если все переменные являются глобальными, воспользуйтесь подстановкой
с символическими ссылками:
$text =~s/\\$(\\w+)/${$1}/g;
Hо если среди переменных могут встречаться лексические (mу)
переменные, следует использовать /её:
$text =~ s/(\\$\\w+)/$1/gee;
*** Комментарий ***
Первый способ фактически сводится к следующему: мы ищем нечто похожее
на имя переменной, а затем интерполируем её значение посредством
символического разыменования (dereferencing). Если $"( содержит строку
somevar, то ${$1} будет равно содержимому $somevar. Такой вариант не
будет работать при действующей директиве use st rict \' rets , потому
что она запрещает символическое разыменование. Приведём пример:
use vars qw($rows $cols);
no strict \'rets\'; # для приведённого ниже ${$1} my $text;
($rows, $cols) = (,^, 80):
$text = q(i am $ rows high and $cols long); # апострофы! $text =~
s/\\$(\\w+)/${$1}/g;
print $text;
I am 24 high and 80 long
Возможно, вам уже приходилось видеть, как модификатор подстановки /е
используется для вычисления заменяющего выражения, а не строки.
Допустим, вам потребовалось удвоить каждое целое число в строке:
$text = "i am 17 years old";
$text ="" s/(\\d+)/2 * $1/eg;
Перед запуском программы, встречая /е при подстановке, Perl
компилирует код заменяющего выражения вместе с остальной программой,
задолго до фактической подстановки. При выполнении подстановки $1
заменяется найденной строкой. В нашем примере будет вычислено
следующее выражение:
2 * 17
Hо если попытаться выполнить следующий фрагмент:
$text = \'i am $age years old\'; # Обратите внимание на апострофы!
$text =~ s/(\\$\\w+)/$1/eg; # HЕВЕРHО
при условии, что $text содержит имя переменной $AGE, Perl послушно
заменит $1 на $AGE и вычислит следующее выражение:
\'$AGE\'
В результате мы возвращаемся к исходной строке. Чтобы получить
значение переменной, необходимо снова вычислить результат. Для этого в
строку добавляется ещё один модификатор /e:
$text =~ s/(\\$\\w+)/$1/eeg; # Hаходит переменные mу()
Да, количество модификаторов /е может быть любым. Только первый
модификатор компилируется вместе с программой и проверяется на
правильность синтаксиса. В результате он работает аналогично
конструкции eval {BLOCK}, хотя и не перехватывает исключений.
Возможно, лучше провести аналогию с do {BLOCK}.
Остальные модификатора! /е ведут себя иначе и больше напоминают
конструкцию eval "STRING". Они не компилируются до выполнения
программы. Маленькое преимущество этой схемы заключается в том, что
вам не придётся вставлять в блок директиву no strict \'refs\'. Есть и
другое огромное преимущество: этот механизм позволяет находить
лексические переменные, созданные с помощью my, - символическое
разыменование на это не способно.
В следующем примере модификатор /х разрешает пропуски и комментарии в
шаблоне подстановки, а модификатор /е вычисляет правостороннее
выражение на программном уровне. Модификатор /е позволяет лучше
управлять обработкой ошибок или других экстренных ситуаций:
# Расширить переменные в $text. Если переменная не определена,
# вставить сообщение об ошибке.
$text =~ s{
\\$ # Hайти знак доллара
(\\w+) # Hайти "слово" и сохранить его в $1
}{
no strict \'refs\';
if (defined $$1) {
$$1; # Расширять только глобальные переменные
} else {
"[NO VARIABLE: \\$$1]; # Сообщение об ошибке
} }еgх;
Обратите внимание на изменение синтаксиса $$1 в Perl 5.004; когда-то
это выражение означало ${$}!, а теперь оно означает ${$1}. Для
обеспечения обратной совместимости в строках оно сохраняет старый
смысл (но выдаёт предупреждение с -w). Запись ${$1} используется в
строках для того, чтобы предотвратить разыменование PID. Если значение
$$ равно 23448, то $$1 в строке превращается в 234481, а не в значение
переменной, имя которой хранится в $1.
===