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

Hi I have a perl regexp question for something I've been struggling with.

Basically I have a file that I wish to match on a particular string

I want to be able to match on 'Servername SERVERNAME' ,where Servername is a constant string and SERVERNAME is variable.

So I want to match on

'Servername myserver'

OR

'Servername DBServer'

as valid examples

However I want to not match on the string if its a certain server name or a certain string comes before Servername.

So I DON'T want to match on the following in an 'IF' condition

'Context Servername DBServer'

Or

'Servername Context'

Any help is very much appreciated.

Replies are listed 'Best First'.
Re: perl regexp question excluding strings
by GrandFather (Saint) on Nov 04, 2011 at 10:29 UTC

    With regular expressions you can often choose the easy way or the hard way. Although it's tempting to try and solve the whole problem with a single regular expression, that is often the hard way and the easy way is to take a step back and use multiple simple expressions instead. Consider:

    use strict; use warnings; my @strings = split "\n", <<STRS; Context Servername Servername Context Servername DBServer Context Servername BogusServer STRS for my $str (@strings) { next if $str =~ /Context\s+Servername|Servername\s+Context/; next if $str !~ /Servername\s+(\w+)/; print "Matched: $1\n"; }

    Prints:

    Matched: DBServer
    True laziness is hard work

      Thanks guys, I'll give both of the idea's a go

      The reason I was trying to do it all in one regular expression is because I'm loading my regular expression in from a hash which is built from a configuration file containing different regexp's. A particular regexp is loaded depending on the situation. Looks like I'm going to have to rethink my design...

      cheers.

Re: perl regexp question excluding strings
by choroba (Cardinal) on Nov 04, 2011 at 10:25 UTC
    Untested:
    while (<>) { if (my $name = /Servername (.*)/) { next if /^Context Servername/; next if /Servername Context/; print $name, "\n"; } }
Re: perl regexp question excluding strings
by AnomalousMonk (Archbishop) on Nov 05, 2011 at 14:10 UTC

    Further to GrandFather's wise advice on regex factoring, here's another approach.

    The idea is that the requirement to "not match ... if ... a certain server name or a certain string comes before Servername" suggests a negative look-behind assertion. The problem with this is the inference I make that the look-behind could be variable-width, and such a look-behind is not directly supported in Perl 5. (I am perhaps improperly reading into the above quotation the possibility that there could be two or more strings of differing lengths to be excluded.)

    A variable-width negative look-behind can be emulated. The trick is that a positive match on one of several completely arbitrary patterns causes a substring needed in a subsequent match to be 'consumed', and then the whole sub-match is 'failed', preventing the subsequent match from succeeding. See  (*SKIP) and  (*FAIL) (only available in 5.10+) in the Special Backtracking Control Verbs section of perlre.

    >perl -wMstrict -le "my @strs = ( 'Servername FOO', 'fine Servername FOO yyy', 'no Servername FOO zzz', 'cool Servername BAR', 'nyet Servername BAR vvv', 'Servername BOFF', 'ok Servername BOFF yyy', 'no Servername BOFF zzz', ); ;; my @names = qw(FOO BAR); my @avoid = qw(no nyet); ;; my $find = join '|', @names; $find = qr{ Servername \s+ (?: $find) }xms; ;; my $not_before = join '|', @avoid; $not_before = qr{ (?: $not_before) \s+ Servername }xms; $not_before = qr{ (?: $not_before (*SKIP)(*FAIL))? }xms; ;; for my $s (@strs) { print qq{'$s'} if $s =~ m{ $not_before $find }xms; } " 'Servername FOO' 'fine Servername FOO yyy' 'cool Servername BAR'