in reply to RegEx - match !foo followed by foo

I read your problem differently than merlyn does. It seems to me that you want to match only if there is gonk at the end of the string, and you only care for up to the first five letters of the word between foobar: and gonk:

use strict; use Test::More tests => 4; sub ungonk { local $_ = $_[0]; if (/^(foobar:.{1,5}).*gonk$/) { return $1 } else { return undef }; }; is ungonk('foobar:hellogonk'), 'foobar:hello'; is ungonk('foobar:gonk'), undef; is ungonk('foobar:higonk'), 'foobar:hi'; is ungonk('foobar:helloworldgonk'), 'foobar:hello';

Replies are listed 'Best First'.
Re^2: RegEx - match !foo followed by foo
by Melly (Chaplain) on Mar 16, 2006 at 13:31 UTC

    Thanks Corion, but I don't think either merlyn's or your solution works... also I made one mistake in my examples:

    foobar:helloworldgonk shouldn't match, because neither gonk nor @ can be found after no more than 5 preceding characters

    Merlyn's solution fails (afaik) because it doesn't require the non-gonk to be followed by gonk (or @).

    Your solution fails (afaik) because foobar:gonkgonk would return 'foobar:gonk' (and should return nothing).

    To put it another way, if 'gonk' was a single character (say '£'), then I would do:

    /foobar:[^£@]{1,5}[£@]/

    Hope that makes it clearer

    Tom Melly, tom@tomandlu.co.uk

      There are the edge cases of foobar:gonkogonk and foobar:ogonkgonk, which I've added to my below test cases. You need to decide if gonkogonk and ogonkgonk should be rejected or accepted. My solution rejects the first but accepts the second case.

      use strict; use Test::More tests => 6; sub ungonk { local $_ = $_[0]; if (/^(foobar:(?!gonk).{1,5})gonk$/) { return $1 } else { return undef }; }; is ungonk('foobar:hellogonk'), 'foobar:hello'; is ungonk('foobar:gonk'), undef; is ungonk('foobar:higonk'), 'foobar:hi'; is ungonk('foobar:helloworldgonk'), undef; is ungonk('foobar:gonkgonk'), undef; is ungonk('foobar:gonkogonk'), undef; is ungonk('foobar:ogonkgonk'), 'ogonk';

      Update: After reading your specification again, you don't want gonk to be found within the first five characters, but it must appear at the end. I think the below program does that, and rejects :ogonkgonk and :gonkogonk.

      use strict; use Test::More tests => 7; sub ungonk { local $_ = $_[0]; if (/^(foobar:(?:(?!gonk).){1,5})gonk$/) { return $1 } else { return undef }; }; is ungonk('foobar:hellogonk'), 'foobar:hello'; is ungonk('foobar:gonk'), undef; is ungonk('foobar:higonk'), 'foobar:hi'; is ungonk('foobar:helloworldgonk'), undef; is ungonk('foobar:gonkgonk'), undef; is ungonk('foobar:gonkogonk'), undef; is ungonk('foobar:ogonkgonk'), undef;

        Hmm, almost - and may be enough for me to work it out <thinks>...</thinks> Nope, still stuck

        foobar:ogonkgonk should return foobar:o

        Tom Melly, tom@tomandlu.co.uk