Reputation: 12381
I want to to do string substitutions in Ruby, but only when certain conditions are not met.
Replace all occurances of 'allegro4' with 'allegro' when the line doesn't start with an #include
statement. I tried this but I am not having any success. The substitution is simply not done.
"#include <allegro4/allegro4.h>".gsub(/(?!#include) allegro4/, 'allegro')
Looking at other example of negative lookaheads and trying different things in irb
lead me to believe that there is something weird going on with negative lookaheads specifically at the beginning of strings.
Upvotes: 0
Views: 463
Reputation: 110675
R = /
\A # match beginning of string
(?!\#include) # do not match '#include' at start of string (negative lookahead)
.*? # match any number of any character
< # match '<'
\K # forget everything matched so far
allegro # match string
(\d+) # match one or more digits in capture group 1
\/allegro # match string
\1 # match the contents of capture group 1
/x # Free-spacing regex definition mode
def replace_unless(str)
str.gsub(R, 'allegro/allegro')
end
replace_unless "cat #include <allegro4/allegro4.h>"
#=> "cat #include <allegro/allegro.h>"
replace_unless "cat #include <allegro4/allegro3.h>"
#=> "cat #include <allegro4/allegro3.h>"
replace_unless "#include <allegro4/allegro4.h>"
#=> "#include <allegro4/allegro4.h>"
I have assumed that the specific string 'allegro' is to be matched and that any non-negative integer can follow both instances of 'allegro', but one cannot have different numbers following the two instances of 'allegro'. If the number must be 4
, replace both (\d+)
and \1
in the regex with 4
. If 'allegro' is merely a stand-in for any string of lower-case letters, the regex can be changed as follows.
R = /
\A # match beginning of string
(?!\#include) # do not match '#include' at start of string (negative lookahead)
.* # match any number of any character
< # match character
\K # forget everything matched so far
([[:lower:]]+) # match one or more lower-case letters in capture group 1
(\d+) # match one or more digits in capture group 2
\/ # match character
\1 # match the contents of capture group 1
\2 # match the contents of capture group 2
/x # Free-spacing regex definition mode
def replace_unless(str)
str.gsub(R, '\1/\1')
end
replace_unless "cat #include <cats9/cats9.h>"
#=> "cat #include <cats/cats.h>"
replace_unless "dog #include <dogs4/dogs3.h>"
#=> "dog #include <dogs4/dogs3.h>"
replace_unless "#include <pigs4/pigs4.h>"
#=> "#include <pigs4/pigs4.h>"
Upvotes: 1