大约一周前我才开始学习 perl。但我对正则表达式功能有基本的了解,比如反向引用、环顾四周等。 所以我写了一个小的正则表达式来匹配数组中的字符串(这个数组代表文件的每一行)只有'{'作为可打印字符。
我的正则表达式是这样的:
for my $f_line (@file_lines) {
my @opening_brace;
if ($f_line =~ /(^[[:blank:]]*(?={))({[[:blank:]]*$)/) {
@opening_brace = $2;
print "opening brace : @opening_brace \n";
}
}
但是,我的正则表达式无法让我进入 if 块,即使它在
grep
上运行良好,当我针对目标文件进行测试时。
我做错了什么?
我试过:
echo "{ " | grep -P '(^[[:blank:]]*(?={))({[[:blank:]]*$)'
得到:
{
哦 我刚刚找到了一个修复程序。 看来我的文件“行”并不是真正的行。 问题在于字符串的逻辑行和文字锚点之间的细微差别,这些锚点表示文件行的开头和结尾,这些锚点是在我将行作为字符串推入数组时创建的。 谢谢你的帮助
这里逐字复制的正则表达式有效
echo "{ " | perl -wnlE'say $1 if /^[[:blank:]]*(?={)({[[:blank:]]*$)/'
打印一行:
{
但是没有
$2
,在问题中使用,†因为显示的正则表达式只捕获一次。似乎您希望前瞻的 (?=...)
也能捕获:它没有。我们需要额外的括号,(?=({))
。因此,要么将其添加到您的正则表达式中,要么保持正则表达式不变并在代码中使用$1
。 (除非数据本身实际上与问题所暗示的不同。)
然后,我不明白为什么要使用前瞻 and 然后为该模式进行实际的消费匹配。 (练习?)
在评论中提到输入可能包含换行符,例如
{\n
。上面使用的问题中的正则表达式仍然有效。
很容易看到的一种方法是删除
-l
开关(所以使用-wnE
),chomp
是换行符。然后将正则表达式应用于以换行符结尾的字符串,添加echo
——我们仍然得到匹配和捕获。 ([[:blank:]]
的 POSIX 字符类不匹配换行符。)
† 一般说明。问题中的
$2
是 assigned 给一个数组,如 @opening_brace = $2
。 can 完成后,数组就有了那个元素。然而,这是非常具有误导性的,并且分配给一个数组会覆盖其中可能已经存在的内容。
我们通过
push @arrayname, LIST
添加到数组,所以在这种情况下是 push @opening_brace, $2;
(但请参阅上面关于 $2
的讨论)。或者,如果数组的字符 @opening_brace
错误地存在,则将 $opening_brace
更正为标量 @
。