Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

negative look behind (again)

by cmic (Novice)
on Jan 20, 2014 at 11:00 UTC ( #1071296=perlquestion: print w/ replies, xml ) Need Help??
cmic has asked for the wisdom of the Perl Monks concerning the following question:

Hi I want to select only lines beginning with TAG1 *and* ending with TAG2. The first try whith positive look behind and positive look ahead works OK. But the second try with negative look behind doesn't. It prints the lines 1, 2, 3 but aloso the TAGS one. Why ?
#!/usr/local/bin/perl #use strict; use warnings; #use re debug; while (<DATA>) { # This section works OK. # if (/(?<=TAG1)(.*)(?=TAG2).*?/x) { # print $1, "\n"; # } if (/^(?<!TAGS)(.*?)(?=TAG2).*$/x ) { print $1, "\n"; } } __DATA__ TAG1 text one TAG2 etc TAG1 text two TAG2 etc TAG1 text three TAG2 etc TAGS text four TAG2 etc TAG1 text five TAGT etc
-- cmic. Life helps. Perl Too.

Comment on negative look behind (again)
Download Code
Re: negative look behind (not needed)
by Anonymous Monk on Jan 20, 2014 at 11:24 UTC

    Why are you using lookarounds at all?

    m{^ starttag (.+?) enddag }xsm

Re: negative look behind (again)
by Anonymous Monk on Jan 20, 2014 at 12:00 UTC

    Why? Because negative lookbehind is satisfied at any position except immediately after the given subpattern. Thus your (.*?) is free to match at the very beginning. Using a lookahead may accomplish what you had in mind (if $1 must contain the start tag).

    if (/^(?!TAGS)(.*?)TAG2/x ) { ...

      [From the OP:]
      if (/^(?<!TAGS)(.*?)(?=TAG2).*$/x ) {
          print $1, "\n";
      }

      Looked at another way,  ^(?<!TAGS) asserts that one wants a string that does not have certain characters before the start of the string. In the absence of the  /m regex modifier, this assertion can never fail!

      With  /m active (allowing  ^ to also match after an embedded newline sequence), an assertion of this sort might be written that could actually fail, but then it would be an assertion about the end of the preceding line, and not about the start of the current line.

Re: negative look behind (again)
by cmic (Novice) on Jan 20, 2014 at 12:22 UTC
    The question is more a technical one: I am re-readning (camel book), Regexp chapter. And I really want to know how to use this negative look behind. Of course, I can do whithout it TMTOWTDI
    -- cmic. Life helps. Perl Too.
Re: negative look behind (again)
by ww (Bishop) on Jan 20, 2014 at 12:56 UTC
    Your data doesn't match your specification...

    You have data items ending with  etc but your narrative specifies "beginning with TAG1 *and* ending with TAG2" (and your code -- very slightly modifed with extra "say" and "use" statements -- at a quick glance seems to [more-or-less] support that narrative).

    #!/usr/local/bin/perl #use strict; use warnings; use 5.016; # 1071296 while (<DATA>) { # This section works OK. say "Positive lookaround first: "; if (/(?<=TAG1)(.*)(?=TAG2).*?/x) { print $1, "\n"; } if (/^(?<!TAGS)(.*?)(?=TAG2).*$/x ) { say "\t Negative lookaround:"; print $1, "\n"; } } # Data now matches narrative; last item, stet, as out-of-spec test __DATA__ TAG1 text one TAG2 TAG1 text two TAG2 TAG1 text three TAG2 TAGS text four TAG2 TAG1 text five TAGT
    OUTPUT:
    Positive lookaround first: text one Negative lookaround: TAG1 text one Positive lookaround first: text two Negative lookaround: TAG1 text two Positive lookaround first: text three Negative lookaround: TAG1 text three Positive lookaround first: Negative lookaround: TAGS text four Positive lookaround first:

    Updated to correct output shown. /me cut'n'pasted the wrong run, lacking tabs for ease of scanning.

    Come, let us reason together: Spirit of the Monastery
Re: negative look behind (again)
by leslie (Pilgrim) on Jan 20, 2014 at 18:25 UTC

    Just try this below code

    #! /usr/bin/perl use strict; use warnings; while (<DATA>) { chomp; if(/^TAG\d{1}.*TAG\d{1}.*/) { print ">>>$_<<\n"; } } __DATA__ TAG1 text one TAG2 etc TAG1 text two TAG2 etc TAG1 text three TAG2 etc TAGS text four TAG2 etc TAG1 text five TAGT etc TAGZ text four TAGX etc
      OK. Leslie. Your code works. But what I want is to make "negative look behind" work with this example. It's just to satisfy my knowledge...
        >perl -wMstrict -le "for ('TAG1 text one TAG2 etc', 'TAGS text ess TAG2 etc', 'TAG1 text two TAG2 etc', ) { print qq{'$_'} if m{ \A .... (?<! TAGS) .* TAG \d }xms; } " 'TAG1 text one TAG2 etc' 'TAG1 text two TAG2 etc'

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1071296]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (7)
As of 2014-08-30 15:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (293 votes), past polls