这个perl脚本没有按照预期替换输入text_str
:
my $text_str ='public class ZipUtilTest extends TestCase {}';
my $find = '^(public class \\w+) extends TestCase \\{';
my $replace = '@RunWith(JUnit4.class)\\n\\1 {';
eval '$text_str =~ ' . "s#$find#$replace#mg";
say "$text_str";
输出(错误):
(JUnit4.class)
public class ZipUtilTest {}
这个修改过的perl脚本(在“replace”中使用“@”转义)按预期进行替换:
my $text_str ='public class ZipUtilTest extends TestCase {}';
my $find = '^(public class \\w+) extends TestCase \\{';
my $replace = '@RunWith(JUnit4.class)\\n\\1 {';
$replace =~ s/@/\\@/g; # Escape '@' to avoid Perl @var interpolation
eval '$text_str =~ ' . "s#$find#$replace#mg";
say "$text_str";
输出(正确):
@RunWith(JUnit4.class)
public class ZipUtilTest {}
看起来“replace”模式中的“@RunWith”被视为Perl @变量,并被插值为空字符串。
有没有比转义模式中的“@”字符更好的方法来处理这个问题?如果我们必须这样做,其他类似“@”的字符需要转义吗?
(Note:这与使用\Q\E来抑制regex meta字符的魔力无关。请不要因为存在这种性质的问题而关闭它。)
3条答案
按热度按时间myss37ts1#
您可以使用正前瞻来匹配
{
,而不用在$1中捕获它,这样替换字符串就不需要包含$1。在构建正则表达式时,最好使用正则表达式引用操作符
qr{}
而不是字符串;它会像正则表达式一样引用,而不是字符串。这可以避免细微的错误。Demonstration .
omvjsjqw2#
您似乎希望从配置文件中加载与语言无关的搜索和替换模式,然后通过Perl脚本应用它们。
如果这是您的目标,那么使用
eval
并不合适,因为正如您所发现的,Perl具有您不想支持的语法。试图通过转义来绕过那些Perl特有的部分是不合理的,因为这可能会变得相当复杂。例如,您考虑过转义
@
,因为它们可能会引入一个数组名,但如果该字符已经被反斜杠转义了呢?正确地处理这一问题将需要几乎完全重新实现Perl的字符串语法,这听起来并不有趣。我要做的是定义我们自己的替换字符串语法,这样我们就完全独立于Perl的语法。
例如,我们可以将替换字符串语法定义为完全逐字的,除了我们支持某些反斜杠转义。假设语法
'\' DIGIT
(如\1
)替换捕获,并且支持通常的反斜杠转义(\b \t \n \v \f \r \" \' \\ \x0A
),它是JavaScript字符串常量、Python 3字符串常量和Perl转义符的公共子集,注意,这些语言在Unicode字符的语法上并不一致。我们可以为这种字符串替换语言实现一个解释器,如下所示:我们将替换字符串解析为一个操作码数组,替换字符串和捕获号,例如,替换模式
abc\1def
将被解析为['abc', 1, 'def']
:我们可以通过循环操作、适当地附加文字字符串或捕获内容来应用这样的替换模式。
现在我们可以在测试用例中使用这些函数:
这将生成预期输出
p8h8hvxi3#
下面是一个有效的版本:直接在替换端使用
$1
,而不是在为它预先做的变量中使用,这样可以节省一些麻烦。模式和替换字符串的变量是从配置文件中读取的。然后我提到的“麻烦”就变得更加严重了。
如果要在替换字符串变量中准备
$1
,则它必须是一个字符串(由字符$
和1
组成),同时它需要成为一个变量,并在正则表达式中进行求值。这意味着变量必须是
eval
-艾德(或者用/ee
运行regex),这就是字符串形式的eval
-- input从外部输入的问题:eval
将评估(运行)任何东西,* 任何 * 代码。我们不需要在配置文件中的文本成为代码的恶意行为,只是考虑打字错误。至于很好地转义(仅)需要转义的内容,我们可以为此做好准备,例如散列:
并在用替换字符串组合变量时使用它。
如果模式和替换都必须来自配置文件 * 并且 * 必须不是Perl特有的,正如一条评论所说,那么我不确定如何改进问题中提供的代码,除非它应该受到严格的保护以防止运行(意外地)坏代码。