hcarreras
hcarreras

Reputation: 4612

opposite of sub in ruby

I want to replace the content (or delete it) that does not match with my filter. I think the perfect description would be an opposite sub. I cannot find anything similar in the docs, and I'm not sure how to invert the regex, but I think a method would probably be the more convenient.

An example of how it would work (I've just changed the words to make it more clear)

"bird.cats.dogs".opposite_sub(/(dogs|cats)\.(dogs|cats)/, '') 
#"cats.dogs"

I hope it's easy enough to understand. Thanks in advance.

Upvotes: 2

Views: 503

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110685

You cannot have a single replacement string because the part of the string that matches the regex might not be at the beginning or end of the string, in which case it's not clear whether the replacement string should precede or follow the matching string. I've therefore written the following with two replacement strings, one for pre-match, the other for post_match. I've made this a method of the String class as that's what you've asked for (though I've given the method a less-perfect name :-) )

class String
  def replace_non_matching(regex, replace_before, replace_after)
    first, match, last = partition(regex)
    replace_before + match + replace_after
  end
end

r = /(dogs|cats)\.(dogs|cats)/

"birds.cats.dogs.pigs".replace_non_matching(r, "", "")
  #=> "cats.dogs"

"birds.cats.dogs".replace_non_matching(r, "snakes.", ".hens")
  #=> "snakes.cats.dogs.hens" 

"birds.cats.dogs.mice.cats.dogs.bats".replace_non_matching(r, "snakes.", ".hens")
  #=> "snakes.cats.dogs.hens" 

Regarding the last example, the method could be modified to replace "birds.", ".mice." and ".bats", but in that case three replacement strings would be needed. In general, determining in advance the number of replacement strings needed could be problematic.

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

String#[] can take a regular expression as its parameter:

▶ "bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#⇒ "cats.dogs"

For multiple matches one can use String#scan:

▶ "bird.cats.dogs.bird.cats.dogs".scan /(?:dogs|cats)\.(?:dogs|cats)/
#⇒ ["cats.dogs", "cats.dogs"]

Upvotes: 4

molf
molf

Reputation: 74945

So you want to extract the part that matches your regex?

You can use String#slice, for example:

"bird.cats.dogs".slice(/(dogs|cats)\.(dogs|cats)/)
#=> "cats.dogs"

And String#[] does the same.

"bird.cats.dogs"[/(dogs|cats)\.(dogs|cats)/]
#=> "cats.dogs"

Upvotes: 3

Related Questions