In Perl, how to count the number of occurences of successful matches based on a condition on their absolute positions

前端 未结 2 1233
星月不相逢
星月不相逢 2021-01-28 17:51

Using just one Perl substitute or matching regular expression statement , how can we modify below code:

I need to modify the value of $pattern<

相关标签:
2条回答
  • 2021-01-28 18:18

    There are quite a few regular expression features that you can use to enforce this type of positional limitation on a pattern match.

    1. Counting matches using a code block within a regex.

      The following uses a boundary condition to enforce position, and then simply counts the number of times that the pattern matches using a code block within the regex.

      I wouldn't necessarily recommend this solution, but it does work for later versions of 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";
      

      Outputs:

      4
      
    2. Enforcing position using a Conditional Expression and pos

      This is similar to the first solution because it also relies on a code block:

      my $count = () = $string =~ /(?(?{pos() % 5 != 0})(*SKIP)(*FAIL))$pattern/g;
      
    3. Using a Positive Lookahead Assertion and boundary conditions.

      The following technique uses \G and boundary conditions to enforce position. The only trick to this is recognizing that we need to gobble the next group of 5 characters so we don't match twice.

      my $count = () = $string =~ m{ \G (?: .{5} )*? (?= ($pattern) ) .{5} }xg;
      
    4. Use Backtracking Control Verbs to intentionally parse the string 5 characters at a time.

      The following looks for a match to our pattern, if it doesn't see it, skips the next 5 characters.

      my $count = () = $string =~ m{ 
          (?= ($pattern) ) .{5}       # Match pattern and move 5 characters
          |
          .{5} (*SKIP)(*FAIL)         # Or just skip 5 characters.
      }xg;
      
    5. Use Position Information after matching.

      The simplest solution is just to match the pattern at all positions, and then use positional information to filter out the matches that we don't want:

      my $count;
      while ( $string =~ /$pattern/g ) {
          $count++ if $-[0] % 5 == 0;
      }
      
    0 讨论(0)
  • 2021-01-28 18:20

    You can use the perl special variable @LAST_MATCH_START to get the output:

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

    Output:

    4
    
    0 讨论(0)
提交回复
热议问题