如何只影响字母,而不影响凯撒密码中的标点符号

How to affect only letters, not punctuation in Caesar Cipher code

我正在尝试在 Ruby 中编写凯撒密码,但在尝试仅将字母更改为数值而不是标点符号时遇到了障碍。

到目前为止,这是我的脚本:

def caesar_cipher(phrase, key)
    array = phrase.split("")        
    number = array.map {|n| n.upcase.ord - (64-key)}
    puts number
end

puts "Script running"
caesar_cipher("Hey what's up", 1)

我尝试使用 select,但我不知道如何 select 仅标点符号或字母。

使用String#gsub仅匹配您要替换的字符。在本例中,它是字母表中的字母,因此您将使用正则表达式 /[a-z]/i.

您可以将一个块传递给 gsub,它将为字符串中的每个匹配项调用,块的 return 值将用作替换。例如:

"Hello, world!".gsub(/[a-z]/i) {|chr| (chr.ord + 1).chr }
# => Ifmmp, xpsme!"

这是您的凯撒密码方法的一个非常有效的版本:

BASE_ORD = 'A'.ord

def caesar_cipher(phrase, key)
  phrase.gsub(/[a-z]/i) do |letter|
    orig_pos = letter.upcase.ord - BASE_ORD
    new_pos = (orig_pos + key) % 26
    (new_pos + BASE_ORD).chr
  end
end

caesar_cipher("Hey, what's up?", 1) # => "IFZ, XIBU'T VQ?"

编辑:

%就是modulo operator。这里用来使new_pos"wrap around"到字母表的开头,如果它大于25.

例如,假设letter"Y"key是5。"Y"在字母表中的位置是24(假设"A"是0), 所以 orig_pos + key 将是 29, 超过了字母表的末尾。

一个解决方案是:

new_pos = orig_pos + key

if new_pos > 25
  new_pos = new_pos - 26
end

这将使 new_pos 3 对应于字母 "D," 成为正确的结果。然而,我们可以更有效地得到相同的结果,方法是将“29 modulo 26”——在 Ruby(以及许多其他语言)中表示为 29 % 26——其中 returns运算的余数为 29 ÷ 26。(因为字母表中有 26 个字母)。 29 % 26为3,同上结果

除了将数字限制在一定范围内,就像我们在这里所做的那样,模运算符还经常用于测试一个数字是否可以被另一个数字整除。例如,您可以通过测试 n % 3 == 0.

来检查 n 是否可以被 3 整除