Проблема строковых кодовых войн (Ruby) - PullRequest
0 голосов
/ 24 февраля 2020

Я работаю над проектом строкового инкрементации на codewars. По сути, написание функции, которая увеличивает строку, для создания новой строки.

Если строка уже заканчивается числом, число должно быть увеличено на 1. Если строка не заканчивается цифрой. число 1 должно быть добавлено к новой строке. Если число имеет начальные нули, следует учитывать количество цифр. foo -> foo1

foo001 -> foo002

foobar23 -> foobar24

foo099 -> foo100

Мой код: input.gsub(/\d/,"")+input.split().map {|x| x[/\d+/].next!}.join(" ") https://repl.it/@tanilserbes / ViolentNoteworthyDowngrade . Он работает на этой площадке, но не работает на кодовых войнах. Я получаю эту ошибку:

main.rb: 5: in block in increment_string': undefined method next! ' для nil: NilClass (NoMethodError) `Есть идеи?
Заранее спасибо!.

Ответы [ 2 ]

2 голосов
/ 24 февраля 2020

Чтобы увидеть, что здесь происходит, полезно запустить каждую из ваших команд по отдельности и посмотреть, что выводит, чтобы отследить ошибку:

input = "foo"
input.gsub(/\d/, "") # => "foo"

Таким образом, левая часть + оператор станет "foo", и теперь нам нужно увидеть, что находится справа от:

input.split # => ["foo"]
["foo"].map { |x| x[/\d+/].next! }

Как видно из вопроса, именно здесь происходит ошибка, поэтому давайте углубимся в код внутри блока map, где ошибка:

["foo"].map { |x| p x }
# Outputs: "foo"

Итак, x == "foo" в этой точке:

["foo"].map { |x| p x[/\d+/] }
# Outputs: nil

Поскольку строка "foo" не имеет любые цифры в нем, регулярное выражение вытаскивает из него цифры, чтобы увеличить их, возвращает nil, а затем, без какой-либо защиты, увеличивает это. NilClass не имеет метода next!, поэтому вы получите ошибку.

Если бы строка была вместо "foo1", вы бы получили:

["foo1"].map { |x| p x[/\d+/] }
# Outputs: "1"

, который возвращает совпавшую строку, а затем позволяет ей вызвать next! (что является синонимом метода String#succ!, вызванного в комментариях). Причина, по которой это работает на игровой площадке, заключается в том, что в строке есть цифры, и она не учитывает и не тестирует случай, когда строки не работают (первый пример в тексте вопроса, где «foo» должен стать «foo1»). «).

1 голос
/ 24 февраля 2020

Вот несколько моментов, которые следует учитывать при разработке вашего решения.

Если бы ваша строка была:

str = "ca9t00456"

желаемое возвращаемое значение было бы:

"ca9t00457"

(Обратите внимание, что решение OP вернуло бы неверный результат ("cat10") для этой строки. Вопрос Codewars не говорит о том, что единственными цифрами в строке являются те, которые находятся в конце; он упоминает только «число» в конце строка ".)

Разумным первым шагом было бы разделить строку на две части:

n = str.index(/\d+\z/)
  #=> 4
prefix = str[0, n]
  #=> "ca9t"
suffix = str[n..-1]
  #=> "00456"

См. String # index . Регулярное выражение /\d+\z/, читает, "соответствует одной или нескольким (+) цифрам (\d), за которыми следует конец строки (\z). Ди git '9' пропускается, потому что за ним не следует ди git и он не находится в конце строки. См. Также См. String # [] .

Возвращаемая строка будет начинаться с (значения, хранящегося в) prefix, поэтому мы можем отложить это в сторону и сосредоточиться на изменении suffix.

Один из подходов был бы:

((suffix.to_i) + 1).to_s
  #=> "457"

, но тогда мы должны были бы добавить правильное число ведущих нулей. Здесь это будет то же самое, что и число ведущих нулей в suffix (2), но если бы suffix было, например, 00999, это было бы только одно (01000). Это может быть сделано, но это грязно.

Более простой способ - использовать метод String # su cc, как @steenslag предлагает в комментариях.

new_suffix = suffix.succ 
  #=> "00457"
"00999".succ
  #=> "01000"

Теперь нам нужно только объединить prefix и new_suffix.

Обратите внимание, что произойдет, если мы выполним succ для всей строки:

"ca9t0456".succ
   #=> "ca9t0457" correct
"ca9t0999".succ
   #=> "ca9t1000" correct
"ca9t9999".succ
   #=> "ca9u0000" incorrect

Как видите, есть проблема с третьим примером. Вот почему я решил разделить строку на две части в качестве первого шага.

Вам нужно исследовать три других случая. Первый - когда префикс является пустой строкой:

str = "00456"

, второй - когда суффикс является пустой строкой:

str = "ca9t"

, а третий - когда строка пуста:

str = ""

Вы можете проверить, работают ли предыдущие вычисления в первом случае.

Во втором случае мы найдем:

n = str.index(/\d+\z/)
  #=> "cat9t".index(/\d+\z/) => nil

nil значение для n говорит нам, что желаемое возвращаемое значение:

str + "1"
  #=> "ca9t" + "1" => "ca9t1"

Будет ли это работать?

...