Как выбрать буквы из строки до заданной точки? - PullRequest
2 голосов
/ 01 июня 2019

Я хотел бы извлечь все согласные в строке перед первой гласной, в идеале без использования регулярных выражений. Например, если у меня есть слово «грузовик», я хотел бы извлечь «tr», для «улицы» я бы хотел извлечь «str».

Я попробовал следующее, но получил ошибку wrong number of arguments (given 0, expected 1) for the execution of the block in vowels.

Может кто-нибудь объяснить, где ошибка или предложить более простой способ сделать это?

vowels = ["a", "e", "i", "o", "u"]

def vowels(words)
  letters = words.split("")
  consonants = []
  letters.each do |letter|
    consonants << letter until vowels.include?(letter)
  end
  consonants
end

Ответы [ 5 ]

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

Использование take_while является семантическим.

word.chars.take_while { |c| vowels.none? c }.join
1 голос
/ 01 июня 2019

Обратите внимание, что ваша функция и массив имеют одно и то же имя, vowels.Это вызывает путаницу - вы можете подумать, что вы вызываете includes? в глобальном массиве vowels, но на самом деле ваш код пытается рекурсивно вызвать вашу функцию с идентичным именем без параметров, что приводит к ошибке.Так как Ruby разрешает вызовы функций без круглых скобок, Ruby обрабатывает эту строку:

vowels.include?(letter)

как

vowels().include?(letter) # <- wrong number of arguments!

Изменение имени вашей функции на что-то отличное от «гласных» вызывает эту ошибку, что делает болеесмысл:

undefined local variable or method `vowels' for main:Object
(repl):7:in `block in function_formerly_known_as_vowels'
(repl):6:in `each'
(repl):6:in `function_formerly_known_as_vowels'
(repl):12:in `<main>'

Это приводит к основной причине: нарушение инкапсуляции.Функция vowels пытается получить доступ к состоянию в глобальной области.Это плохая практика (и она не будет работать в этом коде, поскольку массив vowels на самом деле не является глобальным - ему понадобится префикс $ для имени переменной или другой способ сделать его видимым внутри области действия функции- см. этот ответ для деталей).Вместо этого передайте массив гласных в функцию в качестве параметра (и, возможно, обобщите функцию в процессе) или жестко закодируйте его внутри самой функции, поскольку можно предположить, что гласные не изменятся.

После разрешенияпроблема объема, следующая проблема заключается в том, что until - это цикл.Как только letter является согласной, она будет неоднократно помещаться в массив consonants до тех пор, пока программе не хватит памяти.Вы, вероятно, имели в виду unless.Даже здесь вам нужно будет break или return, чтобы выйти из цикла при нахождении гласного.

Наконец, пара семантических предложений: vowels не очень точное имя функции.Он возвращает согласные до первого гласного, поэтому назовите его как таковой!Параметр "words" может вводить в заблуждение, поскольку он предлагает массив или серию слов, когда ваша функция работает с одним словом (или строкой, в общем случае).

Вот перезапись:

def front_consonants(word)
  vowels = "aeiou"
  consonants = []

  word.each_char do |letter|
    break if vowels.include? letter
    consonants << letter
  end

  consonants.join
end

p front_consonants "stack" # => "st"
1 голос
/ 01 июня 2019

Рассмотрите возможность использования Enumerable # chunk :

VOWELS = ["a", "e", "i", "o", "u"]
word = "truck"
word.chars.chunk { |e| VOWELS.include? e }.first.last.join
#=> "tr"

Первая часть возвращает

word.chars.chunk { |e| VOWELS.include? e }.to_a #=> [[false, ["t", "r"]], [true, ["u"]], [false, ["c", "k"]]]
0 голосов
/ 02 июня 2019

Вы сказали "в идеале, без использования регулярных выражений".Извините, но я думаю, что большинство Rubyists согласятся с тем, что регулярное выражение является здесь инструментом выбора:

"whatchamacallit"[/\A[^aeiou]*/] #=> "wh"
"apple"[/\A[^aeiou]*/]           #=> ""

Регулярное выражение гласит: «соответствует началу строки (\A), за которым следует ноль или более (*) символы, которые не являются (^) гласными ", [^aeiou] представляет собой класс символов .

0 голосов
/ 01 июня 2019
consonants << letter until vowels.include?(letter)

просто заканчивает тем, что нажимает одну и ту же согласную снова и снова (бесконечный цикл).

Как бы я это сделал, это reduce с использованием `break.

Я рекомендую прочитать их, если вы незнакомы

https://apidock.com/ruby/Enumerable/reduce

Как вырваться из рубинового блока?

# better to make this a constant
Vowels = ["a", "e", "i", "o", "u"]

def letters_before_first_vowel(string)
  string.chars.reduce([]) do |result, char|
    break result if Vowels.include?(char)
    result + [char]
  end.join
end

puts letters_before_first_vowel("truck")
# => "tr"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...