代码之家  ›  专栏  ›  技术社区  ›  Kjetil S.

希望perl regexp替换重新开始并避免“1 while”技巧

  •  3
  • Kjetil S.  · 技术社区  · 7 年前

    示例:我要删除中的重复字符 $s 这样地:

    my $s = 'aabbbcbbac';
    1 while $s =~ s/((.).*)\2/$1/;
    print $s, "\n";                     #prints abc
    

    有没有简单快捷的方法来避免 1 while 只需一个技巧就可以删除副本 s///g ?以某种方式让它“重新开始”?通过使用 \G 或者在后面看一下前面?只加 /g 不是解决办法。

    3 回复  |  直到 7 年前
        1
  •  8
  •   ikegami Gilles Quénot    7 年前

    这可以通过后面的可变长度查找来完成,这是不允许的。但是,可变长度的向后看等同于输入的反面可变长度的向前看,所以我们有这个技巧:

    reverse 字符串,使用look ahead删除字符,然后 颠倒 再一次

    $t = reverse $s;
    $t =~ s/(.)(?=.*\1)//sg;
    $s = reverse $t;
    

    如果您有Perl5.14或更高版本,并且可以使用 /r 替换上的修饰符,您将得到

    $s = reverse( reverse($s) =~ s/(.)(?=.*\1)//grs );
    
        2
  •  5
  •   simbabque    7 年前

    可以使用 split , grep 和 join 使用查找哈希。不过,它的可读性可能没那么高。

    my $s = 'aabbbcbbac';
    my %seen;
    $s = join '', grep { !$seen{$_}++ } split //, $s;
    print $s, "\n";
    

    这个输出

    abc
    
        3
  •  1
  •   ysth    7 年前

    不,无法使s///在原始字符串的任何一个位置匹配两次以上,因为非零宽度匹配将前进到下一个位置,并且不允许在同一位置进行两次零宽度匹配,以避免无休止的循环。