darisler has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, Trying to write some code that reads in a list of coordinates, must have an odd number for some odd reason. Here is some working code; but I'd like to know how to define '$coords' recursively, so it would work for any number of coordinates. Also, how do I check how many coordinates I have, when all done?
#!/usr/bin/env perl use v5.16; use strict; my $prBoundaryString = <<endPrBoundary; '( (0.01 0.02) (0.0 1328.23) (0.01 0.02) ) endPrBoundary say "prBoundaryString=$prBoundaryString"; my ($coord,$coords); $coord = qr{ \(\s* (?<x>[\-\.0-9]+)\s+ (?<y>[\-\.0-9]+)\s* \)\s* }x; $coords = qr{ ( $coord $coord $coord ) | ( $coord $coord $coord $coord $coord ) }x; $prBoundaryString =~ m{ \'\(\s*\s* $coords \)\s*$ }x || die "parsePrBoundary: Error parsing prBoundary"; say "-x0=$-{x}[0]"; say "-y0=$-{y}[0]"; say "-x1=$-{x}[1]"; say "-y1=$-{y}[1]"; say "-x2=$-{x}[2]"; say "-y2=$-{y}[2]";

Replies are listed 'Best First'.
Re: qr for recursive regex?
by Limbic~Region (Chancellor) on May 28, 2014 at 18:29 UTC
    darisler,
    I am not sure why you are looking for a recursive regex here. Instead, I would simply match globally (perhaps as an iterator) and count how many matches I had:
    my @result = $prBoundaryString =~ m{$coord}g; # check if scalar (@result / 2) % 2 == 1 # or my $count = 0; while ($prBoundaryString =~ m{$coord}g) { my ($x, $y) = ($1, $2); $count++; }
    Sorry I had to rush this so it is untested and it may not be explained enough but I hope it makes sense.

    Cheers - L~R

      The example I posted is simplified - perhaps too much.

      I really want repetition, not recursion, but ran into roadblock with perl behaviour of only returning the last matches. Here is what I first tried, it only returns the last coordinate pair, which is documented behaviour.

      #!/usr/bin/env perl use v5.16; use strict; my $prBoundaryString = <<endPrBoundary; '( (0.01 0.02) (0.0 1328.23) (0.03 0.04) ) endPrBoundary say "prBoundaryString=$prBoundaryString"; my ($coord,$coords); $coord = qr{ \(\s* (?<x>[\-\.0-9]+)\s+ (?<y>[\-\.0-9]+)\s* \)\s* }x; $coords = qr{ ( ( $coord )+ ) }x; $prBoundaryString =~ m{ \'\(\s*\s* $coords \)\s*$ }x || die "parsePrBoundary: Error parsing prBoundary"; say "-x0=$-{x}[0]"; say "-y0=$-{y}[0]"; say "-x1=$-{x}[1]"; say "-y1=$-{y}[1]"; say "-x2=$-{x}[2]"; say "-y2=$-{y}[2]";
      output: - it only gets the last coordinate.
      prBoundaryString='( (0.01 0.02) (0.0 1328.23) (0.03 0.04) ) -x0=0.03 -y0=0.04 -x1= -y1= -x2= -y2=
        darisler,
        If you use a regex with the global modifier in scalar context, you will get an iterator allowing you to go through each set of matches one at a time (like one of the examples above):
        while ($str =~ m{$your_regex}g) { my ($x, $y) = ($1, $2); # This loop will repeat for as many matches as are in $str }

        Cheers - L~R

Re: qr for recursive regex?
by 2teez (Vicar) on May 28, 2014 at 20:20 UTC

    Hi darisler,
    Trying to write some code that reads in a list of coordinates, must have an odd number for some odd reason... but I'd like to know how to define '$coords' recursively

    Do you have to define '$coords' recursively or repeatedly? And I don't know why you are using your regex like you are doing. If I get what you wanted, you can simply use split to get all the coords into an array, so they are in right order as follow in your original string, then loop for this like so:

    use v5.16; use strict; my $prBoundaryString = <<endPrBoundary; '( (0.01 0.02) (0.0 1328.23) (0.01 0.02) (0.04 0.53) (0.03 44.23) (0.0 1328.23) (0.04 0.53) ) endPrBoundary say "prBoundaryString=$prBoundaryString"; my @pts = grep { /\d+/ } split /\s+|[()]/, $prBoundaryString; my $count = 0; for ( 0 .. $#pts ) { if ( $_ % 2 == 0 ) { print qq[-x$count=$pts[$_]] } else { print qq[-y$count=$pts[$_]]; $count++ } }
    Output:
    prBoundaryString='( (0.01 0.02) (0.0 1328.23) (0.01 0.02) (0.04 0.53) +(0.03 44.23) (0.0 1328.23) (0.04 0.53) ) -x0=0.01 -y0=0.02 -x1=0.0 -y1=1328.23 -x2=0.01 -y2=0.02 -x3=0.04 -y3=0.53 -x4=0.03 -y4=44.23 -x5=0.0 -y5=1328.23 -x6=0.04 -y6=0.53
    Note: I modified the string you gave to show that it would get it in right order.
    Hope this helps

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me