在perl中如何找到与模式不匹配的子字符串

时间:2010-07-14 07:06:54

标签: regex perl

我需要找到补充:

$_ = 'aaaaabaaabaaabacaaaa';

while( /([a][a][a][a])/gc){
    next if pos()%4 != 0;
    my $b_pos = (pos()/4)-1;
    print " aaaa at :$b_pos\n";
}

也就是说,一套4个字符不是'aaaa'。
以下不起作用

$_ = 'aaaaabaaabaaabacaaaa';

while( /([^a][^a][^a][^a])/gc){
    my $b_pos = (pos()/4)-1;
    print "not a at :$b_pos\n";
}

当然我可以这样做

$_ = 'aaaaabaaabaaabacaaaa';

while( /(....)/gc){
    next if $1 eq 'aaaa';
    my $b_pos = (pos()/4)-1;
    print "$1 a at :$b_pos\n";
}

有没有更直接的方式?

为了澄清预期结果,我需要找到所有不是'aaaa'的4字母套件以及那里的位置。
第一个代码输出

 aaaa at :0
 aaaa at :4

第二个代码应输出

not aaaa at :1
not aaaa at :2
not aaaa at :3

第三代码输出,是我正在寻找的

abaa at :1
abaa at :2
abac at :3

我明白我还不够清楚,请接受我的批评。
我想要实现的就像分成一组4个字母的字符串,得到那些没有的组的价值和位置不符合模式。

我的第三个代码给了我预期的结果。它当时读取字符串4字母并处理那些不是'aaaa'的字母 我还发现,感谢您的所有建议,我的第一个代码没有按预期工作,如果pos()%4!= 0,它应该跳过,这意味着该模式跨越两组4.我纠正了代码。

出乎所有人的意料,从我和其他人那里,以下内容并没有输出任何东西

/[^a]{4}/

我应该坚持使用我的第三个代码。

5 个答案:

答案 0 :(得分:4)

/(?!aaaa)/

这是一个负向前瞻,它在模式aaaa不匹配的第一个位置匹配。

可替换地,

/[^a]{4}/

将匹配4个字符,这些字符都不是a

答案 1 :(得分:1)

complemented binding

$string !~ /pattern/;

答案 2 :(得分:1)

编辑:经过一些更多的摆弄,并认为我找到了正确的解决方案,我将留下以前的答案供参考......

似乎/aaaa(??aaaa)....?(??aaaa)..../gc是/ aaaa /的补充,用于您的目的:

$_ = 'aaaaabaaabaaabacaaaa';
while( /aaaa(?!aaaa)....|(?!aaaa)..../gc ){
    my $b_pos = (pos()/4)-1;
    print substr($_,$b_pos*4,4)." at :$b_pos\n";
}

结果如下:

abaa at :1
abaa at :2
abac at :3

上一个回答

负向前瞻不会与“块”迭代相互作用,即使在您的小样本输入中也是如此:

use POSIX floor;
$_ = 'aaaaabaaabaaabacaaaa';
while( /(?!aaaa)..../gc ){
    my $b_pos = floor(pos()/4);
    print " !aaaa at :$b_pos str:".substr($_,$b_pos*4,4);
    print " c_pos:".(pos()-4)." str:".substr($_,(pos()-4),4)."\n";
}

输出:

 !aaaa at :1 str:abaa c_pos:2 str:aaab
 !aaaa at :2 str:abaa c_pos:6 str:aaab
 !aaaa at :3 str:abac c_pos:10 str:aaab
 !aaaa at :4 str:aaaa c_pos:14 str:acaa

这是因为前瞻将逐个字符地进行评估,而不是以4为块进行评估。这意味着在aaaabaaa的情况下,它会检查aaaa然后aaab哪个不会超前匹配aaa因此那些将被消耗,而不是baaa人们可能想要......

然而明智地使用map,grep和split解决问题:

my $c = 0;
print "!aaaa at positions: ", 
      join ",", map { $$_[1] } 
                    grep { $$_[0] !~ /aaaa/ } 
                         map { [$_, $c++ ] } 
                             grep /./, split /(.{4})/, $_;
print "\n";

结果:

!aaaa at positions: 1,2,3

说明:

  1. split /(. {4})/,$ _会将输入拆分为4个字符的块列表
  2. 但是在split中使用regexp捕获可能会导致空块出现在列表中,因此我们使用grep /./
  3. 来消除它们
  4. 现在我们创建输入的元组加上块编号(因此我们需要将$ c初始化为0 ...)
  5. 现在我们过滤掉与'aaaa'
  6. 不匹配的元素
  7. 现在我们映射只检索块号...
  8. 匹配完全输出:

    my $c = 0; 
    print "",  
      join "\n",  
           map { $$_[0]." at: ".$$_[1] }  
               grep { $$_[0] !~ /aaaa/ }  
                    map { [$_, $c++ ] }  
                        grep /./, split /(.{4})/, $_; 
    print "\n"; 
    

答案 3 :(得分:0)

这个怎么样:

/[^a]{4}/

答案 4 :(得分:0)

试试这个:

/(?:(?!aaaa)[a-z]){4}/g

在匹配每个字符之前,前瞻确保它们不是aaaa