I have a bunch of phrases with missing apostrophes, and I have an array of fixes like so:
phrase = "i d let some"
def contractions_to_fix
[
{ missing: "let s", fixed: "let's" },
{ missing: "i d", fixed: "i'd" }
]
end
I'm trying to loop through the array of contractions to replace them, like this:
contractions_to_fix.each do |contraction|
if phrase.include? contraction[:missing]
idea_title.gsub! contraction[:missing], contraction[:fixed]
end
end
The goal, for this example, would be to return "i'd let some"
; however, every regex I've tried so far returns an incorrect response.
For example:
contraction[:missing]
results in"i'd let'some
/\bcontraction[:missing]\b/
results in"i d let some"
Any help would be much appreciated!
CodePudding user response:
The easiest way to code the exact requirement in your title is to flip your condition around: "isn't preceded or followed by a non-space":
idea_title.gsub!(/(?<!\S)#{Regexp.escape(contraction[:missing])}(?!\S)/, contraction[:fixed])
Though /\b#{...}\b/
should work for the example you gave. Your problem is likely the fact that you feed a String
as the pattern into gsub!
instead of Regexp
, so you are literally looking for \b
(backslash and lowercase B
), not a word boundary. Try it with
idea_title.gsub!(/\b#{Regexp.escape(contraction[:missing])}\b/, contraction[:fixed])
CodePudding user response:
arr = [
{ missing: "let s", fixed: "let's" },
{ missing: "i d", fixed: "i'd" }
]
h = arr.reduce({}) { |h,g| h.merge(g[:missing]=>g[:fixed]) }
#=> {"let s"=>"let's", "i d"=>"i'd"}
r = /\b(?:#{h.keys.join('|')})\b/
#=> /\b(?:let s|i d)\b/
"i d want to let some".gsub(r, h)
#=> "i'd want to let some"
This uses the (second) form of String.gsub that takes a hash as a second argument and has no block.
One may alternatively calculate h
as follows.
h = arr.map { |g| g.values_at(:missing, :fixed) }.to_h
#=> {"let s"=>"let's", "i d"=>"i'd"}