【问题标题】:Perl Regex 'e' (eval) modifier with s///Perl Regex 'e' (eval) 修饰符与 s///
【发布时间】:2011-08-30 05:55:25
【问题描述】:

我在理解 /e 正则表达式修饰符的这种简单用法时遇到了一点麻烦。

my $var = 'testing';
$_ = 'In this string we are $var the "e" modifier.';

s/(\$\w+)/$1/ee;

print;

返回:“在这个字符串中,我们正在测试“e”修饰符。”

我不明白为什么需要两个“e”修饰符。据我所见,$1 应该从字符串中捕获“$var”,然后单个“e”修饰符应该能够用它的值替换变量。但是,我一定是误解了一些东西,因为仅使用一个 'e' 修饰符尝试上述代码不会明显替换字符串中的任何内容。

不好意思问了这么简单的问题!

谢谢。

【问题讨论】:

  • 请注意,“e”不是正则表达式修饰符,因为它不会影响正则表达式!它只影响更换部件。所以“e”修改了 s/// 操作符,而不是正则表达式。

标签: regex perl modifier


【解决方案1】:

这不是一个“简单”的问题,所以不要自责。

问题在于,对于单个 /e,RHS 被理解为将其 eval 的结果用于替换的代码。

RHS 是什么?这是$1。如果您评估$1,您会发现其中包含字符串 $var。它不包含所述变量的内容,只是 $ 后跟 v 后跟 a 后跟 r。

因此必须计算两次,一次将$1 转换为$var,然后再次将$var 的先前结果转换为字符串"testing"。您可以通过在 s operator 上使用双 ee 修饰符来做到这一点。

您可以通过一个 /e 与其中两个运行它来轻松检查这一点。这是一个两者的演示,加上第三种使用符号解引用的方法——因为它引用包符号表,所以只适用于包变量。

use v5.10;

our $str = q(In this string we are $var the "e" modifier.);
our $var = q(testing);

V1: {
    local $_ = $str; 
    s/(\$\w+)/$1/e;
    say "version 1: ", $_;

}

V2: {
    local $_ = $str;
    s/(\$\w+)/$1/ee;
    say "version 2: ", $_;
}

V3: {
    no strict "refs";
    local $_ = $str;
    s/\$(\w+)/$$1/e;
    say "version 3: ", $_;
}

运行时,会产生:

version 1: In this string we are $var the "e" modifier.
version 2: In this string we are testing the "e" modifier.
version 3: In this string we are testing the "e" modifier.

【讨论】:

  • 太好了,谢谢。出于好奇,为什么使用 NO 修饰符生成正则表达式 s/(\$\w+)/$1/ 仍将其替换为捕获的值 ($var)?在我看来,这就是第一个 /e 的用途?
  • @user761513:没有修饰符,$1 作为替换文本被用作字符串。使用单个e,它被用作表达式,具有完全相同的结果。要查看差异,请将s/…/$1 (hello)/(字符串)与s/…/uc($1)/e(表达式)进行比较。
  • 具体来说,没有修饰符,替换文本就像一个双引号字符串。因此$1 插值到第一组括号捕获的内容。
【解决方案2】:

需要明确的是,s//ee 表单根本不会修改您的正则表达式模式或正则表达式解释。它是执行正则表达式后对替换侧字符串的可选处理。 (见PERLOP Regex Quote-like operators)

e 或 ee 只是混合到 s/PATTERN/REPLACEMENT/msixpodualgcer 表单中的 PATTERN 端正则表达式选项中。

来自 Perlop:

选项与 m// 相同 添加以下替换 具体选项:

e Evaluate the right side as an expression.
ee  Evaluate the right side as a string then eval the result.
r   Return substitution and leave the original string untouched.

您可以在非正则表达式的情况下看到相同的 e 与 ee 类型行为,如下例所示:

#!/usr/bin/perl 
use warnings;
use strict;

my $var = "var's contents";
my $str='"-> $var <-"';
print eval('$str'), "\n";        # equivalent to s//e
print eval(eval('$str')), "\n";  # equivalent to s//ee

输出:

"-> $var <-"
-> var's contents <-

【讨论】:

  • # use strinct 是做什么的? ;-}
  • [Rejected as an edit] 最后一点,只是为了完整性:您可以添加更多es,并不是因为文档停在那里它不可行:我的 $testing = “呼!”;我的 $var = '$testing'; $_ = '我们是 $var 的“e”修饰符。'; s/(\$\w+)/$1/e;打印; $_ = '我们是 $var 的“e”修饰符。'; s/(\$\w+)/$1/ee;打印; $_ = '我们是 $var 的“e”修饰符。'; s/(\$\w+)/$1/eee;打印;产生我们是 $var 的“e”修饰符。我们正在 $testing "e" 修饰符。我们是呸! “e”修饰符。
  • @thewolf 你能用我的修改来编辑你的帖子吗?
【解决方案3】:

尝试使用最新 perl 包中的重命名实用程序:

rename -v 's/\b(\w)/uc($1)/eg' *

在这里,\b 模式查找单词边界,e 修饰符启用替换中的评估,g 替换所有出现。

您也可以使用以下命令重命名为 camelCase:

rename -v 's/\b(\w)/uc($1)/eg' *
rename -v 's/^(\w)/lc($1)/e' *
rename -v 's/\s+//g' *

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2014-12-09
    • 2014-02-16
    • 2014-05-22
    • 1970-01-01
    • 2013-03-05
    相关资源
    最近更新 更多