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

Normally the way to say "does not match" in perl is !~.

I have a list of regular expressions for use in a simple search filter:

my $sv = _get_search_value(); my %rx = ( equals => qr/^\Q$sv\E$/i, contains => qr/\Q$sv\E/i, 'starts with' => qr/^\Q$sv\E/i, 'ends with' => qr/\Q$sv\E$/i, );

Is there a simple way that I can produce a regex that will match any string not containing $sv?

Help much appreciated.

andramoiennepemousapolutropon

Replies are listed 'Best First'.
Re: reversing a compiled regex?
by dragonchild (Archbishop) on Mar 26, 2003 at 18:01 UTC
    I suppose you could do negative lookahead, but that seems to be overkill. Better, I think, would be to modify your interface so that your caller can indicate what regex he/she wants as well as if this is a postive or negative match. Then, you just use =~ or !~, as appropriate.

    One way to do this while still hiding the operation is to expand your data structure. Instead of one level, go to two levels.

    my %rx = ( equals => [ qr/^\Q$sv\E$/i, 1 ], 'not equals' => [ qr/^\Q$sv\E$/i, 0 ],
    The 1 meaning use =~, the 0 meaning use !~.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      The solution I did indeed use in the end. I think your sig is relevant here ;-)

      Well, almost. Actually I just gave "equals" and "not equals" (et cetera) the same keys in the regex and then did roughly:

      if ($key =~ /not/) { return $string !~ /$rx/; } else { return $string =~ /$rx/; }

      andramoiennepemousapolutropon

        *grins* If it's all you need, then it's all you need. :-)

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: reversing a compiled regex?
by diotalevi (Canon) on Mar 26, 2003 at 18:10 UTC

    [Prepended - This is a slowish way to solve the problem. There's an eval block involved in the (?{$re}) bit which may not fit with your needs. Normally you'd just have not() in your code somewhere and use a normal regex.]

    Here's a thought - use the conditional expression followed by true/false assertions. You may want to read up on it in perlre.

    my $digit = qr/^\d+$/; my $not_digit = reverse_regex_assertion( $digit ); print 0+(1234 =~ $digit), 0+(1234 =~ $not_digit); sub reverse_regex_assertion { my $re = shift; return qr/(?(?{$re})(?!)|(?=))/; } # That expression broken into pieces #qr/(? # Conditional (?(expr) (true) | (false) ) # (?{$re}) # Test $re expression # (?!) # Assert false # | # OR # (?=) # Assert true # )/x
Re: reversing a compiled regex?
by OM_Zen (Scribe) on Mar 26, 2003 at 19:27 UTC
    Hi ,

    The not in can be implemented by this I guess

    my $a = "SCALAR"; my $str = "TT"; my $regexs = qr/[^\Q$str\E]/i; $a =~ s/$regexs/HOO /g; print "[$a]\n"; __END__ [HOOHOOHOOHOOHOOHOO]


      This is not a correct conclusion or suggestion. Take a look at your code again:

      my $regexs = qr/[^\Q$str\E]/i;

      [] is used to define a character class, not a regular expression grouping. The statement above reads: "at least one character not found in $str." The reason your test code did not show you this is because you were matching:

      ($a = "SCALAR") =~ s/[^TT]/HOO/gi;

      Or, simplified:

      ($a = "SCALAR") =~ s/[^T]/HOO/gi;

      Since every character in the string "SCALAR" is "not T", every character is replaced with HOO. The original request was for a method of implementing !// using only //.

      Please put a little more thought into your response... Cheers...

        Hi MarkM ,

        Thanks for the reply , I got the actual post only now. That was totally my mistake . I see the solution from the other fellow reply . I shall surely give a little thought into my response .