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

I need to analyse data used to control machine tool. A sample is shown below.

N335G03X247.16Y580.07K6.89J96.62H1M25 N340M20 N345G45 N350G01X832.56Y692.92C275.44M25 N355M20 N360G46C0 N365G03Y720.88I146.74J13.98H36M25

I need to find rows which have certain patterns. Some of the numbers are fixed others are variable. For example the first four rows can be written as (the variable numbers all are in a <> and some may be integers)

N<n>G03X<x>Y<y>K<k>J<j>H1M25 N<n>M20 N<n>G45 N<n>G01X<x>Y<y>C<c>M25

and I want to find the rows which match these descriptions.
I can see that regular expressions might well be able to do this but I am not sure how to start.

Therefore I would appreciate any pointers and possible examples which will help me to do this.

Replies are listed 'Best First'.
Re: Using regular expressions to find patterns in machine tool data
by Athanasius (Archbishop) on Jun 27, 2015 at 10:07 UTC

    Hello merrymonk,

    My approach is similar to those already given:

    #! perl use strict; use warnings; my $num = qr{ \d+ (?: \. \d* )? }x; my @patterns = ( qr{ ^ N $num G03X $num Y $num K $num J $num H1M25 $ }x, qr{ ^ N $num M20 $ }x, qr{ ^ N $num G45 $ }x, qr{ ^ N $num G01X $num Y $num C $num M25 $ }x, ); my $count = 1; my %patterns = map { $_ => $count++ } @patterns; OUTER: while (my $line = <DATA>) { chomp $line; for (keys %patterns) { if ($line =~ $_) { print "$line matches pattern $patterns{$_}\n"; next OUTER; } } print "No match found for $line\n"; } __DATA__ N335G03X247.16Y580.07K6.89J96.62H1M25 N340M20 N345G45 N350G01X832.56Y692.92C275.44M25 N355M20 N360G46C0 N365G03Y720.88I146.74J13.98H36M25

    Output:

    19:53 >perl 1287_SoPW.pl N335G03X247.16Y580.07K6.89J96.62H1M25 matches pattern 1 N340M20 matches pattern 2 N345G45 matches pattern 3 N350G01X832.56Y692.92C275.44M25 matches pattern 4 N355M20 matches pattern 2 No match found for N360G46C0 No match found for N365G03Y720.88I146.74J13.98H36M25 20:04 >

    Notes:

    • By defining a regular expression which matches a number (integer or floating point) and storing it in $num, I am able to simplify the creation of the longer regular expressions against which the data will be tested. The use of $num, combined with the /x modifier, also makes the regular expressions easier to read and maintain.

    • Storing the regular expressions in a hash makes it straightforward to identify which pattern was matched whenever a match is successful. This could be useful for debugging.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Using regular expressions to find patterns in machine tool data
by FreeBeerReekingMonk (Deacon) on Jun 27, 2015 at 09:07 UTC

    Well, if you have N335G03X247.7.16Y580.07K and your pattern is N<n>G03X<x>Y Then we know that numbers are actual numbers 0-9 and can contain a dot as decimal separator, thus the regular expression to match this is:

    use strict; use warnings; my $line = "N335G03X247.16Y580.07K6.89J96.62H1M25 N340M20 N345G45"; my($n, $x); if($line =~ /N([0-9\.]+)/){ $n = $1 }; if($line =~ /G03X([0-9\.]+)/){ $x = $1 };
    You can then use this to get the rest of the variables, then check if they have the right values... or at least defined, for example if $n and $x has been defined:
    if($n && $x){ print "n=$n and x=$x \n" }
    You can exchange 0-9 with \d, as in:
    if( $line =~ /N([\d\.]+)/ ){ $n = $1 }; if( $line =~ /G03X([\d\.]+)/ ){ $x = $1 };

      you don't need to quote . in a character set match.

      Perl is the programming world's equivalent of English

      Further to GrandFather's reply: Also note that the pattern  [\d.]+ will match  '.1.2.3.4.' or  '1....2' or  '......' which may not be what you want. In defining regexes, specificity is a great virtue. Dealing with regular expressions is like dealing with the Djinn from the bottle: they'll both give you exactly what you ask for, so it's best to ask for exactly what you want!


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

Re: Using regular expressions to find patterns in machine tool data
by hexcoder (Curate) on Jun 27, 2015 at 09:22 UTC
    Hello,

    I assume, you want single matched lines and not blocks of matched lines. Then you could use something like this:

    use strict; use warnings; while (defined(my $line = <DATA>)) { if ($line =~ m{ \A N \d+ G \d+ X \d+ \.? \d* Y \d+ \.? \d* K \d+ \.? \d* J \d+ + \.? \d* H 1 M 25 \n \z | \A N \d+ M 20 \n \z | \A N \d+ G 45 \n \z | \A N \d+ G 01X \d+ \.? \d* Y \d+ \.? \d* C \d+ \.? \d* M 25 \ +n \z }xms) { print $line; } } __DATA__ N335G03X247.16Y580.07K6.89J96.62H1M25 N340M20 N345G45 N350G01X832.56Y692.92C275.44M25 N355M20 N360G46C0 N365G03Y720.88I146.74J13.98H36M25
    which yields
    N335G03X247.16Y580.07K6.89J96.62H1M25 N340M20 N345G45 N350G01X832.56Y692.92C275.44M25 N355M20
    Update: added end-of-line anchors in regular expressions.
Re: Using regular expressions to find patterns in machine tool data
by RichardK (Parson) on Jun 27, 2015 at 10:22 UTC

    As you're new to regex then the tutorial perlretut is a good place to start.

      Thanks for all those comments. I am sure that these will give me a good start (if not end!) to what I have to do.