Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
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
Replies are listed 'Best First'.
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
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"; } }

      Note that

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

      can be written

      if ( $string !~ /pattern/ ) {

      I hope this is of interest.

      Cheers,

      JohnGG

      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)
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"; }

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 drinking their drinks and smoking their pipes about the Monastery: (15)
As of 2015-07-31 15:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (279 votes), past polls