【问题标题】:perl regex match closestperl 正则表达式匹配最接近
【发布时间】:2011-10-29 19:13:40
【问题描述】:

我正在尝试从最后一个壁橱中匹配到最后一个词。

例如,最接近狗的 b

“abcbdog”

应该是“bdog”

但我得到的是“bcbdog”

如何只匹配“dog”之前的最后一次出现的“b”

这是我当前的正则表达式:

/b.*?dog/si

谢谢!

【问题讨论】:

    标签: regex perl match closest


    【解决方案1】:

    正则表达式想要从左到右,但你想从右到左,所以只需反转你的字符串,反转你的模式,然后反转匹配:

    my $search_this  = 'abcbdog';
    my $item_name    = 'dog';
    my $find_closest = 'b';
    
    my $pattern = reverse($item_name)
                . '.*?'
                . reverse($find_closest);
    
    my $reversed     = reverse($search_this);
    $reversed        =~ /$pattern/si;
    my $what_matched = reverse($&);
    print "$what_matched\n";
    # prints bdog
    

    【讨论】:

    • @TLP:这种编辑对你有用吗?我认为人们也会阅读 cmets,但有时我认为是错误的。
    • 开箱即用的好想法! :)
    【解决方案2】:

    试试这个:

    /b[^b]*dog/si
    

    匹配b,然后匹配任何不是b(包括任何内容),然后匹配dog

    【讨论】:

    • 太棒了!这适用于我给出的示例。我现在唯一的问题是,当我将它放入带有变量的脚本中时,如下所示: ($string =~ /$item_name([^$item_name]*$match)/si) 它需要括号中的 $item_name 变量是字面的,它不会匹配:/
    • @srchulo 您要求为文字字符而非变量提供解决方案。如果您发现自己提出了错误的问题,您应该编辑您的问题。
    【解决方案3】:

    TIMTOWTDI:

    此方法甚至可以通过字符串找到多个匹配项,或者如果开始或结束词更常见,则可以进行优化。 编辑:现在使用零宽度匹配来避免删除然后添加开始和结束字符串。

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    use v5.10; #say
    
    my $string = 'abcbdog';
    my $start = 'b';
    my $end = 'dog';
    
    my @found = 
      grep { s/(?<=$end).*// } 
      split( /(?=$start)/, $string );
    
    say for @found;
    

    【讨论】:

    • +1 很好地使用了拆分。虽然您可以使用否定前瞻来代替 map: /(?=$start)/
    • @TLP,是的,这似乎有效。虽然我相信你的意思是把它称为“积极的前瞻”。
    【解决方案4】:

    当你还不知道 dog 之前的最后一个字符是什么时,这才有效:

    my $str = 'abcbdog';
    
    my @r = $str =~ /(.dog)/;
    
    print @r;
    

    打印 bdog

    【讨论】:

      【解决方案5】:

      如果您只是想将最接近的“b”与“狗”(包括狗)进行匹配,那么接受的答案似乎有点复杂,您只需在您要寻找的术语之前进行匹配即可。例如:

      # First example
      my $string1 = 'abcbdog';
      if ( $string1 =~ /.+(b.*dog)/ ) {
          print $1;
          # Returns 'bdog'
      }
      
      # Second example, different string, same regex.
      my $string2 = 'abcbmoretextdog';
      if ( $string2 =~ /.+(b.*dog)/ ) {
          print $1;
          # Returns 'bmoretextdog'
      }
      

      或者我错过了什么?如果要更改捕获的字符串以匹配所需的内容,只需移动括号即可。

      【讨论】:

        【解决方案6】:

        试试这个代码:

        ~/.* b.*?dog/si
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多