在Perl中,如何根据绝对位置的条件计算成功匹配的出现次数

时间:2014-09-05 05:07:42

标签: regex perl

只使用一个 Perl替换或匹配正则表达式语句,我们如何修改下面的代码:

我需要在下面的代码中修改 $ pattern 的值,代码将计算在字符串中找到成功匹配的次数,前提是该成功的绝对位置匹配满足某种条件。

$pattern = "F1";  
$string = "F1234F12F1F1234F12F13";     
$count = 0;      
while ($string =~ /$pattern/g) {$count++} 
print $count;

作为绝对位置条件的一个例子,你可以想到:

ABSOLUTE_POSITION可分为5

在这种情况下,基于上面的 $ string 的值,输出将为:4。


请注意,一旦代码完成,在成功匹配的绝对位置的不同条件下唯一更改的行将是代码的第一行。

感谢您的帮助

2 个答案:

答案 0 :(得分:2)

您可以使用perl特殊变量@LAST_MATCH_START来获取输出:

use strict;
use warnings;

my $pattern = "F1";  
my $string  = "F1234F12F1F1234F12F13";     
my $count;      
while ( $string =~ /$pattern/g ) {
    $count++ if $-[0] % 5 == 0;
} 
print $count;

输出:

4

答案 1 :(得分:0)

您可以使用相当多的正则表达式功能来对模式匹配强制执行此类位置限制。

  1. 使用code block within a regex计算匹配项。

    以下使用边界条件来强制执行位置,然后使用正则表达式中的代码块简单地计算模式匹配的次数。

    我不一定会推荐这个解决方案,但它适用于更高版本的perl:

    use strict;
    use warnings;
    use re 'eval';
    
    my $pattern = qr{F1};  
    my $string  = "F1234F12F1F1234F12F13";     
    
    my $count;
    $string =~ /^(?:.{5})*$pattern(?{ $count++ })(*FAIL)/g;
    
    print $count, "\n";
    

    输出:

    4
    
  2. 使用Conditional Expressionpos

    执行排名

    这与第一个解决方案类似,因为它还依赖于代码块:

    my $count = () = $string =~ /(?(?{pos() % 5 != 0})(*SKIP)(*FAIL))$pattern/g;
    
  3. 使用Positive Lookahead Assertion和边界条件。

    以下技术使用\G和边界条件来强制执行位置。唯一的诀窍是认识到我们需要吞下下一组5个字符,所以我们不会两次匹配。

    my $count = () = $string =~ m{ \G (?: .{5} )*? (?= ($pattern) ) .{5} }xg;
    
  4. 使用Backtracking Control Verbs有意识地一次解析5个字符的字符串。

    以下查找与我们的模式匹配,如果它没有看到它,则跳过接下来的5个字符。

    my $count = () = $string =~ m{ 
        (?= ($pattern) ) .{5}       # Match pattern and move 5 characters
        |
        .{5} (*SKIP)(*FAIL)         # Or just skip 5 characters.
    }xg;
    
  5. 匹配后使用Position Information

    最简单的解决方案是在所有位置匹配模式,然后使用位置信息过滤掉我们不想要的匹配项:

    my $count;
    while ( $string =~ /$pattern/g ) {
        $count++ if $-[0] % 5 == 0;
    }