Таким образом, вопрос требует, чтобы я «Написал метод, который принимает строку и возвращает новую строку, в которой каждый согласный символ удваивается. Гласные (a, e, i, o, u), цифры, знаки препинания и пробелы не должны быть удвоился». Что ж, я быстро понял, что регулярное выражение должно помочь, но я новичок в таких выражениях, и поэтому мне пришлось использовать оператор &&, чтобы заставить мое решение работать. Теперь я уверен, что это легко исправить, но я не смог его создать, поэтому вот мое решение проблемы:
def double_consonants(string)
array = string.chars.map do |char|
if char =~ /[a-z]/i && char =~ /[^aeiou]/i
char * 2
else
char
end
end
array.join
end
Таким образом, double_consonants("Hello World!") правильно выводит "HHellllo WWorrlldd!" но я ищу более краткое решение. Я пробовал [a-z^aeiou]/i и подобные комбинации, но они также удваивали гласные. Так что, если кто-то может проинструктировать меня, как правильно объединить два выражения, а также объяснить мне, почему моя элементарная попытка была ошибочной, я был бы чрезвычайно признателен. Кроме того, любые предложения или исправления в остальной части моего кода также приветствуются.
Попробуйте: if char =~ /[bcdfghjklmnpqrstvwxyz]/i
Да, я знаю, что мой ответ работает, но я искал более простое решение, которое сочетает в себе два моих условия, если это возможно. @SagarPandya
Спасибо @Matt.G, это сработало, но, честно говоря, я искал рабочую версию [a-z^aeiou]/i, чтобы лучше понять механизм регулярных выражений.
Это /[a-z&&[^aeiou]]/
от здесь. Тогда другим способом использования gsub будет str.gsub(/([a-z&&[^aeiou]])/i,'\1\1')
Несколько очень мелких моментов. 1) Начиная с Ruby v2.4 вы можете писать char.match?(/[a-z]/i)
вместо char =~ /[a-z]/i
. Первый, возможно, читается лучше и возвращает логическое значение, а не строковый индекс (вы бы его не использовали) или nil
. 2. Вы можете написать char !~ /aeiou/i
вместо char =~ /[^aeiou]/i
. (продолжение...)
...3. string.chars
возвращает временный массив. Поскольку map
является методом Enumerable
, для него требуется получатель, который является перечислителем, вместо этого вы можете написать string.each_char.map
, поскольку each_char
возвращает перечислитель, а не временный массив, экономя память. Используйте each_char
, за исключением случаев, когда используется цепочка с методом Array
, и в этом случае вы должны использовать chars
(например, string.chars.product(...)
).
Обратите внимание, что вам не нужна переменная array
. Удалите array =
и array.join
и замените end
, который заканчивает блок map
, на end.join
. Напомним, что каждый блок возвращает значение. Вот вариант, который позволяет избежать преобразования в массив и последующего join
, а также включает предложение @Sagar: "Cats!".each_char.with_object('') { |c,s| s << (c.match?(/[a-z&&[^aeiou]]/i) ? c*2 : c) } # #=> "CCattss!"
. Кстати, поскольку ваш код работает, ваш вопрос действительно больше подходит для дочернего сайта SO на Stack Exchange, Обзор кода. Посмотри!
Спасибо, @SagarPanya, ваше решение ближе всего к тому решению, которое я себе представлял.
@CarySwoveland, ты рок-звезда. Ваше более крупное решение было очень тщательным, и ваше предложение использовать матч? вместо метода регулярного выражения =~ имеет смысл и с ним легче работать. Кстати, я буквально завел профиль прямо перед тем, как запостить эту проблему и был в шоке от скорости ответов. Я хочу поблагодарить вас и всех, кто нашел время, чтобы помочь мне.
MAPPING =
(('a'..'z').to_a - %w|a e i o u|).
each_with_object({}) do |s,h|
h[s] = s + s
h[s.upcase] = h[s].upcase
end.tap { |h| h.default_proc = proc { |_,c| c } }
#=> {"b"=>"bb", "c"=>"cc", "d"=>"dd", "f"=>"ff",..."z"=>"zz",
# "B"=>"BB", "C"=>"CC", "D"=>"DD", "F"=>"FF",..."Z"=>"ZZ"}
MAPPING['c'] #=> "cc"
MAPPING['C'] #=> "CC"
MAPPING['a'] #=> "a"
MAPPING['$'] #=> "$"
"Now is the time to party, said 007.".gsub(/./, MAPPING)
#=> "NNoww iss tthhe ttimme tto pparrttyy, ssaidd 007."
Здесь используется форма Строка#gsub, которая использует хэш (MAPPING
) для выполнения замен. Первый аргумент gsub
, регулярное выражение /./
заставляет сопоставляться каждый символ строки.
Чтобы это работало, MAPPING[c]
(c
переменная) должна возвращать c
для каждого символа c
, который не является согласным. Это достигается добавлением процедура по умолчанию (proc { |_,c| c }
) к хешу. См. Хэш#default_proc= и Ядро # нажмите.
Если необходимо преобразовать несколько строк, использование регулярного выражения относительно неэффективно по сравнению с использованием хэша, поскольку сопоставление символа с набором согласных требует линейного поиска, тогда как поиск по хэшу выполняется очень быстро, будучи относительно нечувствительным к количеству ключей. в хеше.
если вам нужно решение регулярного выражения, подобное тому, которое было опубликовано в вопросе, попробуйте регулярное выражение: (?=[a-z])(?![aeiou])(.)
и заменить на \1\1
Переходя к регулярному выражению, упомянутому в вопросе: [a-z^aeiou]
соответствует одному символу в диапазоне между a (index 97)
и z (index 122)
или ^
или a
или e
или i
или o
или u
(без учета регистра) (более подробную информацию см. В описании, приведенном в правом верхнем углу в этом Демо)
Ваш ответ работает.
double_consonants('abcdefg') #=> "abbccddeffgg"
.