Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Invert grep match with qr// variable

by Anonymous Monk
on Feb 06, 2024 at 16:21 UTC ( [id://11157579]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question: (regular expressions)

I'm trying to get the effect of grep(!/re/, @array) with the /re/ saved in a variable. Nothing that I try seems to work. I don't find that there is any way to place the inversion within the regex variable, so I guess that it needs to go in the grep call. Starting with $tmp=qr/pattern/; I've tried grep(!$tmp, @array); and grep(! $tmp, @array); (that has a space added) and grep {! $tmp} @array;, but no joy. What variation would work?

Replies are listed 'Best First'.
Re: Invert grep match with qr// variable
by hv (Prior) on Feb 06, 2024 at 18:27 UTC

    It is possible to put the inversion in the regexp, but I don't recommend it: it will in almost all cases be much less efficient.

    Here's how it works: $string =~ /$re/ matches if $re matches at any point in the string; $string =~ /(?!$re)/ matches if there is any point in the string that does not match $re; $string =~ /^(?!.*$re)/s therefore matches only if there is no point in the string that matches $re, and is therefore the inverse.

    Inverting outside the pattern just requires one of a couple of ways to ensure the interpreter knows it should do a pattern match:

    grep !/$re/, @array; # use // round $re to treat as a pattern match grep $_ !~ $re, @array; # use a negating match

    Note that if $re is a precompiled regexp, perl won't need to recompile it just because you put // round it.

    Hugo

      • .* should be (?s:.*?).
        • Without /s, it could affect whether some strings match or not.
        • Without the non-greedy, it will affect the value of capture vars ($&, $1, etc) on a match. Not relevant in this case.
      • ^ should be be \G
        • This will affect the number of matches when /g is used. Not relevant in this case.
      Cool. Frontpaged the OP for this answer.
Re: Invert grep match with qr// variable
by Corion (Patriarch) on Feb 06, 2024 at 16:33 UTC

    Purely from a syntax point of view, the following would work:

    my @res = grep { !/$tmp/ } @array;

    There is no good general way to negate a (Perl) regular expression. Negative lookahead/lookbehind like (?! and (?<! will easily fail for (say):

    use 5.020; use Data::Dumper; my $tmp = qr/re/; my @positive = grep {/$tmp/} 'rerere', 'foo'; my @negative = grep {/(?!$tmp)/} 'rerere', 'foo'; say Dumper \@positive; # 'rerere' say Dumper \@negative; # 'rerere', 'foo'

    In the past, whenever I wanted this I've used an external variable for the grep result like this:

    use 5.020; use Data::Dumper; my $tmp = qr/re/; my $reverse = 0; # my @positive = grep {!! /$tmp/ xor $reverse } 'rerere', 'foo'; $reverse = 1; my @negative = grep {!! /$tmp/ xor $reverse } 'rerere', 'foo'; say Dumper \@positive; # 'rerere' say Dumper \@negative; # 'foo'

      There is no good general way to negate a (Perl) regular expression.

      See my answer.

Re: Invert grep match with qr// variable
by ikegami (Patriarch) on Feb 06, 2024 at 22:08 UTC

    You could use

    grep( !/$re/, @array )
    grep( $_ !~ $re, @array )

    What about something within the regex itself?

    /$re/
    is effectively short for
    /\G(?s:.*?)$re/

    This is a form we can negate.

    /\G(?!(?s:.*?)$re)/

    So you could use

    grep( /\G(?!(?s:.*?)$re)/, @array )

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11157579]
Approved by Corion
Front-paged by Dallaylaen
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2025-05-20 11:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.