Perl - 前瞻性断言

时间:2014-03-08 01:51:44

标签: perl

我正在尝试为此目的描述一个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) );

您能让我知道如何修复脚本吗?谢谢。

3 个答案:

答案 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));