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

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,

Replies are listed 'Best First'.
Re^6: Regex troubles...
by AnomalousMonk (Archbishop) on Apr 23, 2016 at 19:57 UTC

    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,

        Please see this reply below.


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

Re^6: Regex troubles...
by AnomalousMonk (Archbishop) on Apr 23, 2016 at 20:45 UTC

    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:  <%-{-{-{-<