Issue #5588 has been updated by Suraj Kurapati.


Yui NARUSE wrote:
> I doubt this function under the current implementation should be
> flags because /ruby/v =~ "ruby"  is now useless example.  I think
> people who want to use this negation flag should simply write
> (?:(?!r).).

I respectfully disagree; for me, wholly negated regexps are more
useful than partly negated ones.  Please see my use cases below.

> Moreover it has a bug, for example over
> http://www.ruby-forum.com/topic/133413 If the suffix is not "dog"
> but "tv", the regexp may be /cat((?:(?!cat).)*)tv/.  But as
> following, it has false negative.
>
> irb(main):013:0> /cat((?:(?!cat).)*)tv/=~"cat foo bar catv"
> => nil

It works if you add a word-boundary anchor at the end of "cat":

>> /cat((?:(?!cat\b).)*)tv/=~"cat foo bar catv"
0
>> $&
"cat foo bar catv"

> The missing piece of your proposal is a use case.  All existing
> examples are too artificial.  Design should prior to
> implementations, and use cases should prior to designs.

Very true, thanks for this much needed criticism.

> I'm interesting in the idea negation flag.  But your proposal is
> limited by implementation.

I only have use cases for wholly negated regexps (/.../v):

* some_enumerable.grep(/.../v)
* some_string =~ some_regexp # where some_regexp given by user
* case some_string; when /.../v; end

That is why I became confused when implementing partly negated
regexps (/(?v:)/).

> Use cases I know is
> * comments of C Language: /* ... */
> * SGML CDATA: <![CDATA[ ... ]]>
> * HTML 2.0 (RFC 1866) 3.2.5. Comments: /<!(--[^\-]*(-[^\-]+)*--)*>/
> * HTML 4.0/XML Comments: /<!--[^\-]*(-[^\-]+)*-->/
> * HTTP header: until CRLFCRLF
> * sequences (lines, sentences, paragraphs, and so on) which doesn't include a word

These seem like good use cases of partly negated regexps (/(?v:)/).
----------------------------------------
Feature #5588: add negation flag (v) to Regexp
http://redmine.ruby-lang.org/issues/5588

Author: Suraj Kurapati
Status: Assigned
Priority: Normal
Assignee: Yui NARUSE
Category: core
Target version: 2.0.0


Please add a negation flag (v) to regexps which inverts them:

  "ruby" =~ /perl/v       #=> true   (turn on negation)
  "ruby" !~ /perl/v       #=> false  (turn on negation)
  "ruby" =~ /(?v:perl)/   #=> true   (turn on negation)
  "ruby" !~ /(?v:perl)/   #=> false  (turn on negation)
  "ruby" =~ /(?-v:perl)/  #=> false  (turn off negation)
  "ruby" !~ /(?-v:perl)/  #=> true   (turn off negation)

The flag name "v" comes from the ex(1) command of the same name.

This has beneficial applications where it is sometimes difficult
to construct what you want to match but much easier to construct
what you *do not* want to match.  Having this negation built in
the regexp itself would remove the need for us to change our 
Ruby code to process a regexp in a different way.  

For example, suppose that you are passing a regexp to the `--name`
command-line option of MiniTest.  This regexp tells MiniTest to
only run those tests whose names match.  If Ruby had a negation
flag on its regexps, then it would be suddenly trivial to make
MiniTest skip certain tests by negating the regexp we pass in.

In this manner, we get a beneficial feature without ever changing
our Ruby code (the codebase of MiniTest in this example).  :-)

Thanks for your consideration.


-- 
http://redmine.ruby-lang.org