Просмотр значения переменной Perl, созданной во время выполнения

Мой код ниже:

use strict;

my $store = 'Media Markt';
my $sentence = "I visited [store]";

# Replace characters "[" and "]"
$sentence =~ s/\[/\$/g;
$sentence =~ s/\]//g;

print $sentence;

На экране я вижу следующее:

Я посетил $ store

Можно ли увидеть следующее? Я хочу увидеть стоимость $ store:

Я посетил Media Markt


person kadir_beyazli    schedule 10.02.2017    source источник
comment
см. также: stackoverflow.com/q/1091634/632407   -  person jm666    schedule 10.02.2017
comment
См. Раздел Что мне делать, когда кто-то ответит на мой вопрос?   -  person zdim    schedule 13.02.2017


Ответы (2)


Кажется, вы думаете об использовании строки 'store' для создания имени переменной $store. Это переходит к теме символических ссылок, и вы не хочу туда идти.

Один из способов сделать то, что вы хотите, - создать хеш, который связывает такие строки с соответствующими переменными. Затем захватите заключенные в квадратные скобки строки в предложении и замените их их хеш-значениями.

use warnings;
use strict;

my $store = 'Media Markt';
my $time  = 'morning';

my %repl = ( store => $store, time => $time );

my $sentence = "I visited [store] in the [time]";

$sentence =~ s/\[ ([^]]+) \]/$repl{$1}/gex;

print "$sentence\n";

Это напечатает строку I visited Media Markt in the morning

Регулярное выражение захватывает все, что находится между [ ], с помощью класса отрицательных символов [^]] (любой символ, кроме ]), соответствует один или несколько раз (+). Затем он заменяет его своим значением в хэше, используя /e для оценки стороны замены как выражения. Поскольку скобки также совпадают, они в конечном итоге удаляются. /x позволяет пробелы внутри для удобства.

Для каждой строки, указанной в скобках, в хеше должна быть пара "ключ-значение", иначе вы получите предупреждение. Чтобы учесть это, мы можем предложить альтернативу

$sentence =~ s{\[ ([^]+) \]}{$repl{$1}//"[$1]"}gex;

Оператор defined-or (//) возвращает "[$1]", если $repl{$1} возвращает undef ( нет ключа $1 в хэше или он имеет значение undef). Таким образом, строки, не имеющие хеш-пар, не изменяются. Я изменил разделители на s{}{}, чтобы внутри можно было использовать //.

Это не позволяет вложение (например, [store [name]]), не обрабатывает многострочные строки и имеет другие ограничения. Но это должно работать в разумных случаях.

person zdim    schedule 10.02.2017
comment
OP может использовать только массив объектов, если она думает о динамически добавляемом коде. - person Pavel; 18.02.2017
comment
@paveljurca Я полностью согласен с тем, что есть другие способы реализовать то, что кажется идеей, и что подход ОО был бы хорош. - person zdim; 19.02.2017

Как я уже говорил вам в группе Perl Programmers в Facebook, это очень похоже на один из ответов в Perl FAQ.

Как я могу раскрыть переменные в текстовые строки?

Если вы можете этого избежать, не делайте этого или если вы можете использовать систему шаблонов, такую ​​как Text :: Template или Template Toolkit, сделайте это вместо этого. Возможно, вы даже сможете выполнить эту работу с помощью sprintf или printf:

my $string = sprintf 'Say hello to %s and %s', $foo, $bar;

Однако для одноразового простого случая, когда я не хочу извлекать полную систему шаблонов, я буду использовать строку, в которой есть две скалярные переменные Perl. В этом примере я хочу расширить $ foo и $ bar до значений их переменных:

my $foo = 'Fred';
my $bar = 'Barney';
$string = 'Say hello to $foo and $bar';

Один из способов сделать это - использовать оператор подстановки и двойной флаг /e. Первый /e оценивает $1 на стороне замены и превращает его в $foo. Второй /e начинается с $foo и заменяет его своим значением. $foo затем превращается в «Фред», и это, наконец, то, что остается в строке:

$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'

/e также будет игнорировать нарушения строгого, заменяя неопределенные имена переменных пустой строкой. Поскольку я использую флаг /e (даже дважды!), У меня те же проблемы безопасности, что и с eval в его строковой форме. Если в $foo есть что-то странное, может быть, что-то вроде @{[ system "rm -rf /" ]}, тогда я могу попасть в беду.

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

my $string = 'This has $foo and $bar';
my %Replacements = (
    foo  => 'Fred',
    );
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
            exists $Replacements{$1} ? $Replacements{$1} : '???'
            /eg;
print $string;

И фактический (но действительно не рекомендуемый - по причинам, указанным в FAQ выше) ответ на ваш вопрос:

$sentence =~ s/\[(\w+)]/'$' . $1/ee;
person Dave Cross    schedule 10.02.2017