Вращение букв в строке так, что каждая буква смещается на другую букву на n мест

ruby

3577 просмотра

4 ответа

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

Я получил следующий код:

def play_pass(str, n)
  letters = ('a'..'z').to_a
  str.chars.map {|x| letters.include?(x.downcase) ? (x.ord + n).chr : x}.join
end

Это работает для большинства писем

Моя проблема в том, что если я пытаюсь сместиться yна 2 места, я должен получить, aно вместо этого я получаю характер[

Куда я иду не так?

Автор: KVyas Источник Размещён: 12.11.2019 09:02

Ответы (4)


3 плюса

Решение

Попробуй это:

def play_pass(str, n)
  letters = ('a'..'z').to_a
  str.chars.map {|x| letters.include?(x.downcase) ? 
     letters[letters.find_index(x.down_case) + n - letters.size] : x}.join
end

p play_pass("abcdefghijklmnopqrstuvwxyz", 2)

Выход

"cdefghijklmnopqrstuvwxyzab"
[Finished in 0.3s]

Как это устроено

lettersэто массив символов aдля zтого, что OP имеет в своем коде. Мы перебираем все символы в strи находим его индекс в lettersмассиве. Затем мы добавляем nк этому индексу, чтобы получить смещенный символ. Чтобы избежать падения массива, мы вычитаем letters.size(в данном случае 26), чтобы наш поиск lettersвыполнялся с использованием значения между 0и 25.

Например: в сценарии, на который указал OP, если смещаемый символ был y, то добавление 2 к его индексу в lettersдаст нам смещенный индекс 26( 24это индекс yв lettersмассиве, 2это число символов, которые мы смещаем в тестовом примере) - Чтобы заставить lettersсебя вести себя как круговой массив и не встречать индекс из исключений связанного типа, мы вычитаем letters.sizeиз 26сдвинутого индекса. Таким образом, мы получаем индекс 0, который представляет символ, aкоторый является тем, что нас интересует.

Другой пример - случай aсмещения индекса 0 + 2 = 2. Когда мы вычитаем letters.sizeэто, мы получаем -24. Ruby допускает отрицательные индексы, в которых поиск элемента массива выполняется с обратной стороны, и он разрешает исправить элемент. Индекс -1такой же, как индекс (size-1), аналогично, значение индекса -sizeравно индексу 0.

Автор: Wand Maker Размещён: 18.07.2015 09:58

3 плюса

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

def play_pass(str, n)
  letters = ('a'..'z').to_a

  str.chars.map do |x| 
    if letters.include?(x.downcase)
      idx = letters.index(x)
      new_idx = (idx + n) % letters.length
      letters[new_idx]
    else
      x
    end
  end.join

end

play_pass('ay1', 2) # => "ca1"

Ключом к успеху здесь является оператор по модулю (%) . Мы используем, чтобы получить индекс символа подстановки из lettersмассива. Это гарантирует, что индекс всегда будет в пределах массива. Вместо того, чтобы идти до конца, он оборачивается.

Читайте об этом. Это полезно во многих местах.

Автор: Sergio Tulentsev Размещён: 18.07.2015 09:49

3 плюса

У массивов есть rotateметод:

def play_pass(str,n)
  abc = ("a".."z").to_a.join
  abc_rot = abc.chars.rotate(n).join
  str.tr(abc, abc_rot)
end

p play_pass("abcdefghijklmnopqrstuvwxyz", 2)
# => "cdefghijklmnopqrstuvwxyzab"

Негатив nвращается в другую сторону.

Автор: steenslag Размещён: 18.07.2015 11:22

2 плюса

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

Автор: Scott Hunter Размещён: 18.07.2015 09:51
Вопросы из категории :
32x32