【问题标题】:Seeing value of Perl variable created at runtime查看运行时创建的 Perl 变量的值
【发布时间】:2017-08-27 15:40:02
【问题描述】:

我的代码如下:

use strict;

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

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

print $sentence;

我在屏幕上看到以下内容:

我去过$store

是否可以看到以下内容?我想看看 $store 的价值:

我参观了媒体市场

【问题讨论】:

标签: perl runtime display


【解决方案1】:

您似乎正在考虑使用字符串'store' 来构建变量名称$store。这涉及到symbolic references 的主题,你do not want to 去那里。

做你想做的事情的一种方法是构建一个哈希,将这些字符串与相应的变量相关联。然后捕获句子中括号内的字符串,并用它们的哈希值替换它们

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这一行

正则表达式通过使用negated character class [^]]] 以外的任何字符)捕获[ ] 之间的任何内容,匹配一次或多次(+)。然后它用它在哈希中的值替换它,使用/e 将替换端评估为表达式。由于括号也匹配,因此它们最终被删除。 /x 允许内部有空格,以便于阅读。

对于括号中的每个字符串,哈希中必须有一个键值对,否则您会收到警告。为了解决这个问题,我们可以提供替代方案

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

defined-or operator (//) 如果 $repl{$1} 返回 undef(哈希中没有键 $1,或者它有 undef 值),则返回 "[$1]"。因此,没有哈希对的字符串是不变的。我把分隔符改成了s{}{},这样//就可以在里面使用了。

这不允许嵌套(如[store [name]]),不处理多行字符串,并且有其他限制。但它应该适用于合理的情况。

【讨论】:

  • 如果她考虑动态添加的代码,OP 可能只使用一组对象。
  • @paveljurca 我完全同意还有其他方法可以追求似乎是这个想法,OO 方法会很好。
【解决方案2】:

正如我在 Perl Programmers Facebook 小组中告诉您的,这与 Perl 常见问题解答中的答案之一非常相似。

How can I expand variables in text strings?

如果可以避免,请不要这样做,或者如果您可以使用模板系统,例如 Text::Template 或 Template Toolkit,请改为这样做。您甚至可以使用sprintfprintf 完成工作:

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 变成了“Fred”,这就是字符串中剩下的内容:

$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;

您的问题的实际答案(但真的不推荐 - 原因在上面的常见问题解答中解释)是:

$sentence =~ s/\[(\w+)]/'$' . $1/ee;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    相关资源
    最近更新 更多