views:

467

answers:

6

I fairly new to regular expressions and need some help. I need to filter some lines using regex in Perl. I am going to pass the regex to another function so it needs to be done in a single line.

I want to select only lines that contain "too long"and that don't begin with "SKIPPING"

Here are my test strings:

SKIPPING this bond since maturity too long
TKIPPING this bond since maturity too long
SLAPPING this bond since maturity too long
Hello this maturity too long
this is too long
hello there

The regex rule should match the following on 'too long":

SKIPPING this bond since maturity too long
SLAPPING this bond since maturity too long
Hello this maturity too long
this is too long

and it should skip:

"hello there" because it doesn't contain 'too long'
"SKIPPING this bond since maturity too long" because it containst 'SKIPPING'

A: 

Using negative lookbehind:

(?<!^SKIPPING)too long$
Thom Smith
Doesn't work. Try it.
chaos
I'm unsure about the ?<!^ syntax, but it really ought to look like: (?<!^SKIPPING).*too long
Jeremy Powell
You can't use a variable-length lookbehind.
Axeman
@Jeremy Powell: no, that matches because there are several places where (?<!^SKIPPING) is true, even if the line doesn't begin with SKIPPING.
ysth
+10  A: 

Personally, I'd do this as two separate regex just to make it clearer.

while (<FILE>)
{
  next if /^SKIPPING/;
  next if !/too long/;

   ... do stuff
}
Paul Tomblin
-1 in Not An Answer.
Daniel
What do you mean "Not An Answer"? It accomplishes exactly what he wants, just not in precisely the way he thought to do it. To me, that's an answer.
Paul Tomblin
+1  A: 

Use a lookahead; see this explanation of regex lookaround.

^(?!SKIPPING).*too long
Al
That site is plain wrong about the syntax for negative look-behind, unfortunately.
Daniel
@Daniel: no, it's not. I think you are confused here.
ysth
@Daniel: How is the site wrong? Negative lookbehind takes the form `(?<!...)` in every regex flavor I know (that supports lookbehind). Perhaps you're thinking of negative **lookahead**, `(?!...)`.
Alan Moore
@Alan M: The site is indeed right and my answer was a negative lookahead, but I thought it was worth mentioning that some (albeit very few) regex flavours use the syntax (...)\@<!
Al
+11  A: 
/^(?!SKIPPING).*too long/
chaos
Very cool. Thanks.I have a ways to go learning regex!
autodidact
THIS is how negative look-behind is done in Perl. No `<` sign.
Daniel
Actually, that's a negative lookahead. Negative lookbehind does indeed have a `<`... the syntax is `(?<!pattern)`.
chaos
+3  A: 

I suspect you maybe after a single regex however I prefer to split into something more readable like this:

use strict;
use warnings;

for my $line ( <DATA> ) {
    next  if $line =~ m/^SKIPPING/;
    next  if $line !~ m/too long/;

    # do something with $line
    chomp $line;
    say "Found: ", $line, ':length=', length( $line );
}

__DATA__
SKIPPING this bond since maturity too long
TKIPPING this bond since maturity too long
SLAPPING this bond since maturity too long
Hello this maturity too long
this is too long
hello there

/I3az/

draegtun
A: 
/^(?<!SKIPPING).*too long$/

Matches the lines you're looking for. The dollar sign at the end causes it to match only strings that end with "too long".

Hope this helps!

diogoriba