我正在尝试为此目的描述一个perl脚本:
a = ~b & ~c; ==> a = (~b) & (~c);
a = ~b & (~c); ==> a = (~b) & (~c);
所以我用lookahead断言插入这样的括号。这是测试代码。
#!/usr/local/bin/perl5 -w
use strict;
use warnings;
my $line;
my @lines;
@lines = (
"assign a = ~b & ~c;",
"assign a = (~b) & (~c);",
"assign a = ( ~b & ~c );",
"assign a = (b & ~c );"
);
foreach $line (@lines) {
print " $line\n";
$line =~ s/(?!\(\s*)~\w+(?!\s*\))/\($&\)/g;
print ">> $line\n\n";
}
它看起来与上面的例子有关。但是,它不适用于此。
assign a = ~b & ~c;
>> assign a = (~b) & (~c); <== OK
assign a = (~b) & (~c);
>> assign a = (~b) & (~c); <== OK
assign a = ( ~b & ~c);
>> assign a = ( (~b) & ~c); <== X. I want ( (~b) & (~c));
assign a = ( ~b & ~c );
>> assign a = ( (~b) & ~c ); <== X. I want ( (~b) & (~c) );
您能让我知道如何修复脚本吗?谢谢。
答案 0 :(得分:0)
使用前瞻和后瞻断言的目标并不能真正为您带来任何好处。在我看来,将代码分解为两个步骤会更容易。捕获前缀为〜的变量的一步,以及第二部分,以查看它们是否被平衡括号包围。
use strict;
use warnings;
while (<DATA>) {
chomp(my $src = <DATA>);
chomp(my $test = <DATA>);
$src =~ s{([(]?~\w+[)]?)}{
my $str = $1;
$str =~ /^\(.*\)$/ ? $str : "($str)";
}eg;
print "test $test\n";
print $src eq $test ? ' ok ' : ' FAIL! ';
print "$src\n";
}
__DATA__
Test:
a = ~b & ~c;
a = (~b) & (~c);
Test:
a = (~b) & (~c);
a = (~b) & (~c);
Test:
a = ( ~b & ~c);
a = ( (~b) & (~c));
Test:
a = ( ~b & ~c );
a = ( (~b) & (~c) );
结果:
test a = (~b) & (~c);
ok a = (~b) & (~c);
test a = (~b) & (~c);
ok a = (~b) & (~c);
test a = ( (~b) & (~c));
ok a = ( (~b) & (~c));
test a = ( (~b) & (~c) );
ok a = ( (~b) & (~c) );
答案 1 :(得分:0)
使用单个正则表达式无法轻松完成所要求的内容。
问题在于,如果不编写递归正则表达式模式,就无法计算嵌套括号的数量,因此在~c
结束时,简单正则表达式无法知道关闭表达式需要多少个括号。
可以使用更复杂的正则表达式,但在Perl循环中对字符串进行标记化也会更容易。
你必须处理像a & ~b & c | (d | ~e & f)
这样的东西吗?
答案 2 :(得分:0)
你可以用一个正则表达式做到这一点,就在这里;
$line =~ s/(?|([^\(])(~\w+)(.)|(.)(~\w+)([^\)]))/$1\($2\)$3/g;
你的reqex并没有按照你的想法行事。
$line =~ s/(?!\(\s*)~\w+(?!\s*\))/\($&\)/g;
第一部分“(?!(\ s *)〜”将永远不会匹配。请记住,前瞻和后视是零宽度断言。我喜欢将它们视为匹配字母之间的空格。(?!(\ s *)〜表示你要匹配一个“〜”字符,但是在“〜”字符前面的空格中,你想要预见并确保你看不到“(”和空格。好吧,如果你在“〜”之前的空间中,你“永远不会看到”(“。如果你在一个”(“,负面向前看可能无法匹配(就像你想要的那样)但你从来没有匹配过无论如何,“〜”。
如果之前的字符不是“(”并且后面的字符不是“)”,那么您正在尝试匹配。但是你想要的是匹配前面的字符不是“(”或者后面的字符不是“)”。所以你需要一个条件分支,如果没有“(”在前面,一个匹配,如果没有“),则需要匹配。”
我使用了一个条件分支,(?|告诉引擎存储这样捕获的子匹配;
(?|([^\\(])(~\w+)(.)|(.)(~\w+)([^\\)]))
$1 $2 $3 |$1 $2 $3
而不是这个
([^\\(])(~\w+)(.)|(.)(~\w+)([^\\)]))
$1 $2 $3 |$4 $5 $6
我使用(。)使〜\ w部分始终为$ 2,然后在输出中的$ 2附近放一个“(”“)”
我的输出
分配a = ~b&amp; 〜C。;
指定a =(~b)&amp; (〜C);
指定a =(~b)&amp; (〜C);
指定a =(~b)&amp; (〜C);
指定a =(~b&amp; ~c);
指定a =((~b)&amp;(~c));
指定a =(~b&amp; ~c);
指定a =((~b)&amp;(~c));
指定a =(~b&amp; ~c);
指定a =((~b)&amp;(~c));
指定a =(~b&amp; ~c);
指定a =((~b)&amp;(~c));