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

Dear Monks
I want to perform a pattern matching, but it seems that I have some problems capturing the desired patterns. Consider the following lines from a matrix
-8-18 -9-10 -8 -7 -9-10 -9 -6 -5 -8 12 -7-10 -8 -8 -8 -8 -6 -3 2 2 -2 -8 1 -2 -5 -1 -4 -6 6 -4 -6 -5 -1 0 -8 -6 -6 3 -6 -3 -6 -2 -5 -5 -5 -4 4 -3 -2 -2 -3 -5 1 3 -7 -4 3 1 -6 -5 -6 4 -5 -6 -5 -6 3 1 -5 -3 -2 -5 -1 3 -4 -3 4 2 -8 -6 -7 -8 -8 -8 7 -8 -9 -9 -7 -8 -6 -8 -4 -7 -9 -9 -8

I want to capture every number (negative or positive), but as you can see, although the obvious separator is the space, sometimes the numbers are next to each other.
I tried this:
if($all_matrix_competitor=~/^([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+) +\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0, +5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\ +d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+ +)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0,5}([\d\-]+)\s{0 +,5}[\d\-]+\s+/)

because I thought the \s{0,5} means  match space 0 up to 5 times, but it doesn't work...
Can you help me fix this?

Replies are listed 'Best First'.
Re: Help with pattern matching quantifiers
by toolic (Bishop) on Oct 24, 2016 at 17:55 UTC
    Since your lines are fixed-width, you can use unpack:
    use warnings; use strict; while (<DATA>) { chomp; my $template = 'A3' x 20; my @nums = unpack $template, $_; } __DATA__ -8-18 -9-10 -8 -7 -9-10 -9 -6 -5 -8 12 -7-10 -8 -8 -8 -8 -6 -3 2 2 -2 -8 1 -2 -5 -1 -4 -6 6 -4 -6 -5 -1 0 -8 -6 -6 3 -6 -3 -6 -2 -5 -5 -5 -4 4 -3 -2 -2 -3 -5 1 3 -7 -4 3 1 -6 -5 -6 4 -5 -6 -5 -6 3 1 -5 -3 -2 -5 -1 3 -4 -3 4 2 -8 -6 -7 -8 -8 -8 7 -8 -9 -9 -7 -8 -6 -8 -4 -7 -9 -9 -8

    I added a single space to the beginning of every line so that each number would occupy 3 columns. If that is not the case with your actual input, the template just needs to be adjusted.

      Oh wow, I did not know this command!!
      Thank you very much!
Re: Help with pattern matching quantifiers
by tybalt89 (Monsignor) on Oct 24, 2016 at 18:11 UTC

    Just regex for what you want...

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1174610 use strict; use warnings; while(<DATA>) { my @values = /-?\d+/g; print "@values\n"; } __DATA__ -8-18 -9-10 -8 -7 -9-10 -9 -6 -5 -8 12 -7-10 -8 -8 -8 -8 -6 -3 2 2 -2 -8 1 -2 -5 -1 -4 -6 6 -4 -6 -5 -1 0 -8 -6 -6 3 -6 -3 -6 -2 -5 -5 -5 -4 4 -3 -2 -2 -3 -5 1 3 -7 -4 3 1 -6 -5 -6 4 -5 -6 -5 -6 3 1 -5 -3 -2 -5 -1 3 -4 -3 4 2 -8 -6 -7 -8 -8 -8 7 -8 -9 -9 -7 -8 -6 -8 -4 -7 -9 -9 -8
      Ah damn, I missed that!
      But thanks a lot!
Re: Help with pattern matching quantifiers
by ww (Archbishop) on Oct 24, 2016 at 19:14 UTC

    ... or just use split:

    #!/usr/bin/perl use strict; use warnings; use 5.018; #1174610 my $data="-8-18 -9-10 -8 -7 -9-10 -9 -6 -5 -8 12 -7-10 -8 -8 -8 -8 -6 -3 2 2 -2 -8 1 -2 -5 -1 -4 -6 6 -4 -6 -5 -1 0 -8 -6 -6 3 -6 -3 -6 -2 -5 -5 -5 -4 4 -3 -2 -2 -3 -5 1 3 -7 -4 3 1 -6 -5 -6 4 -5 -6 -5 -6 3 1 -5 -3 -2 -5 -1 3 -4 -3 4 2 -8 -6 -7 -8 -8 -8 7 -8 -9 -9 -7 -8 -6 -8 -4 -7 -9 -9 -8"; my @data = split(/ +/,$data); my $i=1; for my $item(@data) { if ( $item =~/\d+-\d+/ ) { $item =~ s/(-\d+)/ $1/g; if ($i == 38 ) { print "\n$item "; $i = 1; }else{ print "$item "; $i = $i+3; } }else{ if ($i == 38 ) { print "\n$item "; $i = 1; }else{ print "$item "; $i = $i+3; } } } =head C:\> 1174610.pl -8 -18 -9 -10 -8 -7 -9 -10 -9 -6 -5 -8 12 -7 -10 -8 -8 + -8 -8 -6 -3 2 2 -2 -8 1 -2 -5 -1 -4 -6 6 -4 -6 -5 -1 0 -8 -6 + -6 3 -6 -3 -6 -2 -5 -5 -5 -4 4 -3 -2 -2 -3 -5 1 3 -7 +-4 3 1 -6 -5 -6 4 -5 -6 -5 -6 3 1 -5 -3 -2 -5 -1 3 -4 - +3 4 2 -8 -6 -7 -8 -8 -8 7 -8 -9 -9 -7 -8 -6 -8 -4 -7 -9 + -9 -8 =cut

    But the preceding reply (Re: Help with pattern matching quantifiers from tybalt89) is preferable, both for use of  __DATA__ and for the consistency of spacing between values in the output.

    But it intrigued me to write the extra code to hold line lengths to a relatively narrow page or screen.

      #!/usr/bin/perl use strict; use warnings; while(<DATA>) { my @values = map { split /\d\K\b/ } split ' '; print "@values\n"; } __DATA__ -8-18 -9-10 -8 -7 -9-10 -9 -6 -5 -8 12 -7-10 -8 -8 -8 -8 -6 -3 2 2 -2 -8 1 -2 -5 -1 -4 -6 6 -4 -6 -5 -1 0 -8 -6 -6 3 -6 -3 -6 -2 -5 -5 -5 -4 4 -3 -2 -2 -3 -5 1 3 -7 -4 3 1 -6 -5 -6 4 -5 -6 -5 -6 3 1 -5 -3 -2 -5 -1 3 -4 -3 4 2 -8 -6 -7 -8 -8 -8 7 -8 -9 -9 -7 -8 -6 -8 -4 -7 -9 -9 -8
      Or split by any num of spaces, and additionally split with zero-length matches (find decimal, don't grab previous, find word bound. (e.g.: '-8-18' -> ('-8', '-18')).

      Look, that your regex ([\d\-]+) will take both numbers '-8-18' into $1.