in reply to Re^3: Regex troubles...
in thread Regex troubles...

That doesn't seem to yield any output that I can understand. Why three 'b1' 'b2' 'b3' from ab1b2b3b4d and nothing from any of the others?

c:\@Work\Perl\monks>perl -e "use warnings; use strict; use feature qw{ say }; ;; for my $string (qw(ab1b2b3b4d ab5b6b7d ab8b9d abxd ad)) { my @two; my @matches = $string =~ /(a) (b.(?{ push @two, $2 if defined $2 }))+ (d)/x; say for @matches, '---', @two, '======'; } " a b4 d --- b1 b2 b3 ====== a b7 d --- ====== a b9 d --- ====== a bx d --- ====== --- ======

Update: "This is perl 5, version 14, subversion 4 (v5.14.4) built for MSWin32-x86-multi-thread"


Give a man a fish:  <%-{-{-{-<

Replies are listed 'Best First'.
Re^5: Regex troubles...
by choroba (Cardinal) on Apr 23, 2016 at 19:28 UTC
    Weird, I'm getting a different output:
    a b4 d --- b1 b2 b3 ====== a b7 d --- b5 b6 ====== a b9 d --- b8 ====== a bx d --- ====== --- ======

    This is perl 5, version 20, subversion 1 (v5.20.1) built for x86_64-linux-thread-multi

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Update: While the  (?: (b.) (?{ push @two, $2 }))+ approach discussed in this reply can certainly work, I think I would prefer the two-step approach outlined in choroba's reply above for its greater readability and maintainability.

      If I take the for-loop out of the equation, I get something closer to what I expect (still Strawberry 5.14.4.1):

      c:\@Work\Perl\monks>perl -wMstrict -le "my $string = 'ab1b2b3b4d'; my @two; my @matches = $string =~ /(a) (b.(?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'ab5b6b7d'; @two = (); @matches = $string =~ /(a) (b.(?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'ab8b9d'; @two = (); @matches = $string =~ /(a) (b.(?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'abxd'; @two = (); @matches = $string =~ /(a) (b.(?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'ad'; @two = (); @matches = $string =~ /(a) (b.(?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; " 'ab1b2b3b4d' -> all:(a b4 d) -> 2:(b1 b2 b3) 'ab5b6b7d' -> all:(a b7 d) -> 2:(b5 b6) 'ab8b9d' -> all:(a b9 d) -> 2:(b8) 'abxd' -> all:(a bx d) -> 2:() 'ad' -> all:() -> 2:()
      And if I re-arrange the capturing, I get exactly what I expect:
      c:\@Work\Perl\monks>perl -wMstrict -le "my $string = 'ab1b2b3b4d'; my @two; my @matches = $string =~ /(a) (?: (b.) (?{ push @two, $2 if defined $2 }) +)+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'ab5b6b7d'; @two = (); @matches = $string =~ /(a) (?: (b.) (?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'ab8b9d'; @two = (); @matches = $string =~ /(a) (?: (b.) (?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'abxd'; @two = (); @matches = $string =~ /(a) (?: (b.) (?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; ;; $string = 'ad'; @two = (); @matches = $string =~ /(a) (?: (b.) (?{ push @two, $2 if defined $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; " 'ab1b2b3b4d' -> all:(a b4 d) -> 2:(b1 b2 b3 b4) 'ab5b6b7d' -> all:(a b7 d) -> 2:(b5 b6 b7) 'ab8b9d' -> all:(a b9 d) -> 2:(b8 b9) 'abxd' -> all:(a bx d) -> 2:(bx) 'ad' -> all:() -> 2:()

      Update: The expression
          (?: (b.) (?{ push @two, $2 if defined $2 }))+
      works just as well without the statement modifier:
          (?: (b.) (?{ push @two, $2 }))+
      I don't understand the use of the statement modifier: Could  $2 ever be undefined in this situation?


      Give a man a fish:  <%-{-{-{-<

        Without the modifier, I'm getting one more element in the array which is undefined.

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Ok, it looks like the for-loop business is just some bug that got fixed between (my) version 5.14.4.1 and (your) version 5.20.

      As to the difference between
          (b.(?{ push @two, $2 if defined $2 }))+
      and
          (?: (b.) (?{ push @two, $2 }))+

      It seems to me that in the first expression, the location of the  (?{ ... }) sub-expression within the second capture group means that on the first occasion that  b. can match within string, the capture group has not actually "closed" yet, and so  $2 is undefined. On each subsequent occasion, the previous capture to  $2 is what gets pushed to the array. So, the  @two array is always "one behind" in its contents if the first (undefined) value of  $2 is excluded.

      In the second expression, the second capture group is always fully closed at the moment it is pushed to the  @two array, so no weirdness.


      Give a man a fish:  <%-{-{-{-<

Re^5: Regex troubles...
by Anonymous Monk on Apr 23, 2016 at 19:56 UTC

    This one works for me.

    #!/usr/bin/perl use warnings; use strict; for my $string (qw(ab1b2b3b4d ab5b6b7d ab8b9d abxd ad)) { my @two; my @matches = $string =~ /(a) (?:(b.)(?{ push @two, $2 }))+ (d)/x; @matches and splice @matches, 1, 1, @two; print "@matches\n"; }

      If I put the for-loop back into the unrolled loop code, I start to see weird stuff again (still Strawberry 5.14.4.1):

      c:\@Work\Perl\monks>perl -wMstrict -le "for my $string (qw(ab1b2b3b4d ab5b6b7d ab8b9d abxd ad)) { my @two; my @matches = $string =~ /(a) (?: (b.) (?{ push @two, $2 }))+ (d)/x; print qq{'$string' -> all:(@matches) -> 2:(@two)}; } " 'ab1b2b3b4d' -> all:(a b4 d) -> 2:(b1 b2 b3 b4) 'ab5b6b7d' -> all:(a b7 d) -> 2:() 'ab8b9d' -> all:(a b9 d) -> 2:() 'abxd' -> all:(a bx d) -> 2:() 'ad' -> all:() -> 2:()
      What Perl version are you using?


      Give a man a fish:  <%-{-{-{-<

        Probably related to the changes in perl 5.18.

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

        Try putting it in a file and running from there. Personally I would not trust Window's shell quoting.