Как заменить только гласные слова, которые соответствуют словам в данном массиве, на «*»? - PullRequest
0 голосов
/ 08 июня 2019

Мне нужно создать метод ruby, который принимает строку и массив, и если любое из слов в строке совпадает со словами в данном массиве, тогда все гласные из соответствующих слов в строке должны быть заменены на " *». Я пытался сделать это с помощью регулярных выражений и «если условие», но я не знаю, почему это не работает. Я был бы очень признателен, если бы кто-нибудь мог объяснить мне, где я ошибся и как я могу получить этот код правильно.

def censor(sentence, arr)
    if arr.include? sentence.downcase
      sentence.downcase.gsub(/[aeiou]/, "*")
    end
end


puts censor("Gosh, it's so hot", ["gosh", "hot", "shoot", "so"])

#expected_output = "G*sh, it's s* h*t"

Ответы [ 2 ]

1 голос
/ 08 июня 2019

are.include? sentence.downcase гласит: «Если один из элементов arr равен sentence.downcase ...», а не то, что вы хотите.

baddies = ["gosh", "it's", "hot", "shoot", "so"]
sentence = "Gosh, it's so very hot"

r = /\b#{baddies.join('|')}\b/i
  #=> /\bgosh|it's|hot|shoot|so\b/i 
sentence.gsub(r) { |w| w.gsub(/[aeiou]/i, '*') }
  #=> "G*sh *t's s* very h*t"

В регулярном выражении \b - это разрыв слова , а #{baddies.join('|')} требует совпадения с одним из baddies. Разрывы слов должны избегать, например, "so" соответствия "solo" или "possible". В качестве альтернативы можно написать:

/\b#{Regexp.union(baddies).source}\b/
  #=> /\bgosh|it's|hot|shoot|so\b/

См. Regexp :: union и Regexp # source . source необходим, потому что Regexp.union(baddies) не зависит от модификатора безразличия (i).

Другой подход состоит в том, чтобы разбить предложение на слова, манипулировать каждым словом, а затем объединить все части, чтобы сформировать новое предложение. Одна из сложностей этого подхода связана с персонажем "'", который выполняет двойную функцию в качестве одинарной кавычки и апостроф. Рассмотрим

sentence = "She liked  the song, 'don't box me in'"
baddies = ["don't"]

подход, который я здесь дал, дает правильный результат:

r = /\b#{baddies.join('|')}\b/i
  #=> /\bdon't\b/i 
sentence.gsub(r) { |w| w.gsub(/[aeiou]/i, '*') }
  #=> "She liked the song 'd*n't box me in'" 

Если вместо этого мы разделим предложение на части, мы можем попробовать следующее:

sentence.split(/([\p{Punct}' ])/)
  #=> ["She", " ", "liked", " ", "", " ", "the", " ", "song", ",", "",
  #    " ", "", "'", "don", "'", "t", " ", "box", " ", "me", " ", "in", "'"]

Как видно, регулярное выражение делится "don't" на "don" и "'t", а не на то, что мы хотим. Очевидно, что различие между одинарными кавычками и апострофами является нетривиальной задачей. Это затрудняется тем фактом, что слова могут начинаться или заканчиваться апострофами ("'twas"), а за большинством существительных в притяжательной форме, оканчивающихся на "s", следует апостроф ("Chris' car").

0 голосов
/ 08 июня 2019

Ваш код не возвращает никакого значения, если условие действительно.

Один из вариантов - разделить слова на пробелы и знаки препинания, манипулировать, а затем снова соединиться:

def censor(sentence, arr)
  words = sentence.scan(/[\w'-]+|[.,!?]+/) # this splits the senctence into an array of words and punctuation
  res = []
  words.each do |word|
    word = word.gsub(/[aeiou]/, "*") if arr.include? word.downcase
    res << word
  end
  res.join(' ') # add spaces also before punctuation
end


puts censor("Gosh, it's so hot", ["gosh", "hot", "shoot", "so"])
#=> G*sh , it's s* h*t

Обратите внимание, что res.join(' ') добавить пробелы также перед пунктуацией.Я не очень хорош с регулярным выражением, но это может решить:

res.join(' ').gsub(/ [.,!?]/) { |punct| "#{punct}".strip }
#=> G*sh, it's s* h*t

Эта часть words = sentence.scan(/[\w'-]+|[.,!?]+/) возвращает ["Gosh", ",", "it's", "so", "hot"]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...