Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Regex: negative look ahead

by fcaw1 (Initiate)
on Apr 10, 2012 at 10:44 UTC ( #964306=perlquestion: print w/ replies, xml ) Need Help??
fcaw1 has asked for the wisdom of the Perl Monks concerning the following question:

Hi There I was wondering if you could advise why the following look ahead regex is not working properly. I would not expect the string to match because of the negative look ahead: CODE:

#!/app/perl-5.8/bin/perl my $string = "ERROR blah license will expire"; print `/app/perl-5.8/bin/perl -version` . "\n\n"; if ( $string =~ /(ERROR.*?(?!(Error processing Cancel Execution|licens +e will expire)))/ ){ print "MATCHED\n"; } else { print "NOT MATCHED\n"; }

RESULT:

$ ./regex.pl This is perl, v5.8.3 built for sun4-solaris Copyright 1987-2003, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using `man perl' or `perldoc perl'. If you have access to + the Internet, point your browser at http://www.perl.com/, the Perl Home Pa +ge. MATCHED

Many thanks for your help! Andy

Comment on Regex: negative look ahead
Select or Download Code
Re: Regex: negative look ahead
by Anonymous Monk on Apr 10, 2012 at 11:21 UTC
    This is because you did not understood the regular expressions at the fundamental level.

    .*?
    zero chars -> true -> after the current position is not (?!....) -> true -> return true

    Use something like:
    my $string = "ERROR blah license will expire"; if ($string =~ /^ERROR\b.+?(?:Error processing Cancel Execution|licens +e will expire)\b/m) { print "NOT MATCHED\n"; } else { print "MATCHED\n"; }
    or:
    if ($string =~ /^ERROR\b/m and $string !~ /\b(?:Error processing Cance +l Execution|license will expire)\b/) { print "MATCHED\n"; } else { print "NOT MATCHED\n"; }
Re: Regex: negative look ahead
by halfcountplus (Hermit) on Apr 10, 2012 at 11:42 UTC

    If the goal here is to do things with strings which do not match a pattern, don't try to use a negative look-ahead -- just negate the test:

    my @strings = ( "ERROR blah license will expire", "ERROR blah something else", "ERROR blah Error processing Cancel Execution", ); foreach (@strings) { if (!($_ =~ /^ERROR.+?(Error processing Cancel Execution|license w +ill expire)$/)) { print "Do something with '$_'\n"; } }
      Hi there I am writing a script with tails a log file and for each line runs multiple regular expressions against it (which are contained in a config file). Below are some examples of the log lines
      ERROR 2012-04-02 05:00:18 Error processing Cancel Execution '2012-CSNY +1CMR-1-20120402-1247 52938803o122h090000507' with LHDRSeqId 'CSNY1CMR +1-1333315812780-2759'. [2012-04-02 07:04:27,275][ERROR][101574:Company:japan][analytics.bond. +BondAlibImpl] ALIB license will expire in29 days. Please upgrade lice +nse file under /app/license 2012-04-02 05:00:18,810[ERROR] limitCheck: error while checking instru +ction xxx.core.biz.order.instruction.EquityOrderSubmitInstruction(tsI +d=20120402-090237887-340-509,order=20120402-090237880-767-508:TS)

      With my original regular expression I would want to ignore the first two lines but match the third line. Thanks!

        It could be a good idea to split the big regex.

        A good example: if you want to match lines with the words 'red' and 'dog'.

        The first idea is often to write something like: $line =~ /red.*dog|dog.*red/

        but there is a better way: $line=~/dog/ and $line=~/red/

        So, it's probably better to treat each exclusion with one regex:  next if /regex/;

        while (my $line = <DATA>) { next if $line =~ /^ERROR.*?Error processing Cancel Execution/; next if $line =~ /ERROR.*?license will expire/; print "Do something with the line: $line"; } __DATA__ ERROR 2012-04-02 05:00:18 Error processing Cancel Execution '2012-CSNY +1CMR-1-20120402-1247 52938803o122h090000507' with LHDRSeqId 'CSNY1CMR +1-1333315812780-2759'. [2012-04-02 07:04:27,275][ERROR][101574:Company:japan][analytics.bond. +BondAlibImpl] ALIB license will expire in29 days. Please upgrade lice +nse file under /app/license 2012-04-02 05:00:18,810[ERROR] limitCheck: error while checking instru +ction xxx.core.biz.order.instruction.EquityOrderSubmitInstruction(tsI +d=20120402-090237887-340-509,order=20120402-090237880-767-508:TS)

      Note that

      if ( ! ( $string =~ /pattern/ ) ) {

      can be written

      if ( $string !~ /pattern/ ) {

      I hope this is of interest.

      Cheers,

      JohnGG

Re: Regex: negative look ahead
by JavaFan (Canon) on Apr 10, 2012 at 12:49 UTC
    It seems you want to write a pattern that says "match PAT1, and there should not be PAT2 somewhere after it". You can write that as:
    /PAT1(?!.*PAT2)/s
    or, in your case, as
    $string =~ /^ERROR(?!.*\b(?:Error processing Cancel Execution|license +will expire)\b)/ms

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://964306]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (10)
As of 2014-10-20 21:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (92 votes), past polls