in reply to RegEx - match pattern not followed by literal

Perhaps using a negative lookahead?

$foo =~ /$users_regex(?!,v$)/

From perldoc perlre:

"(?!pattern)"

A zero-width negative look-ahead assertion. For example "/foo(?!bar)/" matches any occurrence of "foo" that isn't followed by "bar". Note however that look-ahead and look- behind are NOT the same thing. You cannot use this for look-behind.

If you are looking for a "bar" that isn't preceded by a "foo", "/(?!foo)bar/" will not do what you want. That's because the "(?!foo)" is just saying that the next thing can- not be "foo"--and it's not, it's a "bar", so "foobar" will match. You would have to do something like "/(?!foo)...bar/" for that. We say "like" because there's the case of your "bar" not having three characters before it. You could cover that this way: "/(?:(?!foo)...|^.{0,2})bar/". Sometimes it's still easier just to say:

if (/bar/ && $` !~ /foo$/)

Update: Fixed formatting, and adding a comment that the documentation does suggest, as Fletch suggests, that it's sometimes still easier to do what Melly is originally doing.



--chargrill
s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; = qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)

Replies are listed 'Best First'.
Re^2: RegEx - match pattern not followed by literal
by ikegami (Patriarch) on Oct 12, 2006 at 15:39 UTC
    No, that doesn't work.
    $users_regexp = qr/^./s; 'abc,v' = /$users_regex(?!,v$)/; # Matches, but it shouldn't. $users_regexp = qr/^.*$/s; 'abc,v' = /$users_regex(?!,v$)/; # Matches, but it shouldn't. $users_regexp = qr/,/; 'abc,v' = /$users_regex(?!,v$)/; # Matches, but it shouldn't.

    Solution:

    /^(?=.*?$users_regex)(?!.*?,v$)/s
    which simplifies to
    /^(?!.*,v$).*?$users_regex/s

    Of course, this is not nearly as readable as the original.

    Updated to show more examples where the parent doesn't work.

      Heh - yeah, looks like the single-regex solution is just too darned ugly (and I'd feel guilty handing that on to be maintained).

      I'll stick with my original two regex solution (but implement that bastard Fletch's suggestion to swap the regexes and check for ,v$ first)

      I guess I was just suprised that the reverse, /$users_regex,v$/, was so easy, but handling NOT ,v$ is so tricky...

      Tom Melly, tom@tomandlu.co.uk

        Regexps can do 'followed by' and 'or' easily, but not 'and'.

        I just thought of another solution:

        /$users_regex .*\z (?<!,v) (?<!,v\n)/xs

        Or if you really meant /,v\z/:

        /$users_regex .*\z (?<!,v)/xs
Re^2: RegEx - match pattern not followed by literal
by johngg (Canon) on Oct 12, 2006 at 15:37 UTC
    I think your negative look-ahead needs to be something like (?!.*,v$) because you don't know where the user-supplied regex is going to leave off matching. I agree with Fletch, however, as the optimisation game is probably not worth the candle.

    Cheers,

    JohnGG

      I don't think a negative look ahead will work - .*(?!,v) will still match foo,v since the .* can just suck up the ,v

      Tom Melly, tom@tomandlu.co.uk
        Yes, perhaps that needs to be non-greedy like (?!.*?,v$) but note that the .*? is inside the assertion.

        Cheers,

        JohnGG