旋转字符串中的字母,以便每个字母被n个位置移动到另一个字母

时间:2015-07-18 09:36:24

标签: ruby

我的任务是提出一种编码字符串的方法。除其他外,我需要将每个字母移动一个给定的数字,但转换后的字母必须是一个字母(循环移位)。

到目前为止,我已经获得了以下代码:

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,但我得到的字符为[

我哪里错了?

4 个答案:

答案 0 :(得分: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"

这里成功的关键是modulo operator (%)。我们用来从letters数组中获取替换字符的索引。它保证索引始终在数组的范围内。它没有超越结束,而是包裹着。

阅读它。它在许多地方都很有用。

答案 1 :(得分: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是一个字符az的数组,就像OP在代码中的方式一样。 我们迭代str中的所有字符,并在letters数组中找到它的索引。然后我们将n添加到该索引以获取移位的字符。为了避免从数组中删除,我们减去letters.size(在本例中为26),以便我们使用letters和{{1}之间的值完成对0的查找}}。

例如:在OP指出的场景中,如果要移动的角色是25,那么在y中为其索引添加2会给我们移位索引letters2624数组中y的索引,letters是我们在测试用例中移位的数字字符) - 使2表现得像圆形数组,并且没有遇到索引超出绑定类型的异常,我们从letters移位索引中减去letters.size。因此,我们得到索引26,它代表我们感兴趣的char 0

另一个例子是a的情况 - 这里移位的索引将是a。当我们从中减去0 + 2 = 2时,我们得到letters.size。 Ruby允许负数索引,其中数组元素的查找是从反向完成的,它将解析为纠正元素。索引-24与索引-1相同,同样,(size-1)的索引值等于索引-size

答案 2 :(得分: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以另一种方式旋转。

答案 3 :(得分:2)

如果您的代码出错,那么当移位的字母的字符代码比原始代码更小时,您的代码总是会添加一个正值来进行移位。您首先需要检测您何时处于这种情况(例如,如果移位的字母大于z),然后进行适当的修复(提示:考虑您想要的字符代码与你现在要来了。)