2011-05-21 174 views
25

我在理解这个简单的/ e正则表达式修饰符的使用方面有点麻烦。Perl正则表达式'e'(eval)修饰符s ///

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

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

print; 

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

我看不出为什么需要两个'e'修饰符。据我所知,$ 1应该从字符串中捕获'$ var',然后一个'e'修饰符就可以用它的值替换该变量。然而,我必须误解某些东西,因为只用一个'e'修饰符来尝试上面的代码并不会明显地替换字符串中的任何东西。

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

谢谢。

+4

注意,“E”是不是一个正则表达式修改,因为它不影响正则表达式!它只影响更换零件。所以“e”修改s ///运算符,而不是正则表达式。 – tadmc 2011-05-21 15:16:24

回答

36

这不完全是一个“简单”的问题,所以不要打垮自己。

问题在于,对于单个/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. 
+0

太好了,谢谢。 作为一个好奇心,为什么使用NO修饰符生成正则表达式s /(\ $ \ w +)/ $ 1 /仍然将其替换为捕获值($ var)?在我看来,这是第一个/ e在那里? – Pete171 2011-05-21 14:33:37

+2

@ user761513:没有修饰符时,作为替换文本的'$ 1'用作字符串。用一个'e',它被用作表达式,结果完全一样。为了查看它们之间的区别,比较's/.../$ 1(hello)/'(一个字符串)和's/.../uc($ 1)/ e'(一个表达式)。 – Gilles 2011-05-21 14:37:41

+1

具体而言,没有修饰符时,替换文本就像一个_double quoted_字符串。因此,'$ 1'内插到第一组括号捕获的内容。 – pjf 2011-05-21 17:39:08

6

要明确的是,s//ee形式不改变你的正则表达式模式或正则表达式的解释都没有。在执行正则表达式之后,它是可选的替换边字符串处理。 (见​​)

eee一下就混合到s/PATTERN/REPLACEMENT/msixpodualgcer形成图案侧正则表达式的选项。

从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 VS 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 <- 
+1

'#使用strict'做什么? ; - } – dawg 2011-05-21 18:00:27

+1

@drewk:'#use strinct do?'告诉世界我不能拼写...错别字修正... – 2011-05-21 22:50:55

+0

[拒绝作为编辑] 最后一点,为了完整:您可以添加偶数更多'e's,这不是因为文档在那里停止,它不可行: my $ testing ='Phew!'; my $ var ='$ testing'; $ _ ='我们是$ var“e”修饰符。 s /(\ $ \ w +)/ $ 1/e; print; $ _ ='我们是$ var“e”修饰符。 s /(\ $ \ w +)/ $ 1/ee; print; $ _ ='我们是$ var“e”修饰符。 s /(\ $ \ w +)/ $ 1/eee; print; 生产 我们是$ var“e”修饰符。 我们正在测试“e”修饰符。 我们是唷! “e”修饰符。 – OmarOthman 2015-08-03 19:05:25

0

尝试从最新的perl的包重命名工具:

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

这里,模式\b查找单词边界,e修改使评价替代,并g取代所有发生。

您还可以重命名以首字母大写:

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