Home > Blockchain >  gsub regex only match if beginning of string or has space
gsub regex only match if beginning of string or has space

Time:12-21

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"}
  • Related