我是一個 Ruby 初學者,我正在開發一個密碼程式。它需要一個短語,將字串轉換為數字,使用給定值遞增數字,然后將它們再次轉換為字串。我想知道如何保持非字母符號不變。像“!”或空格。我寫的代碼如下:
def caesar_cypher ( phrase, number=0)
letters = phrase.downcase.split(//)
letters_to_numbers= letters.map { |idx| idx.ord }
incrementor = letters_to_numbers.map { |idx| idx number}
numbers_to_letters = incrementor.map { |idx| idx.chr}.join.capitalize
p numbers_to_letters
#binding.pry
end
caesar_cypher("Hello world!", 4)
caesar_cypher("What a string!", 6)
uj5u.com熱心網友回復:
使用 Array#rotate 和 Hash#fetch 的解決方案
是的,您可以通過未修改的字符傳遞字符,但要這樣做,您需要定義什么是“字母”以及您想在 #map 塊中的編碼中包含或排除的內容。這是一種稍微不同的方法來解決這些問題,但也更短,并增加了一些額外的靈活性。
- 創建一個包含英文字母表中所有大寫和小寫字符的陣列,并使用Array#rotate的反向散列值將每個字符分配給一個替換值,其中旋轉值是您可重現的密碼密鑰。
- 當您沒有加密值時發出警告,因為輪換是
key % 26 == 0,但無論如何都允許它。這有助于測驗。否則,如果您不想允許純文本結果,您可以簡單地引發例外,或者為key設定默認值。 - 不要大寫你的句子。這限制了您的隨機性,并防止您為大寫字母設定單獨的值。
- 使用Hash#fetch的默認值允許您回傳任何不在您的 Hash 中的字符而不對其進行編碼,因此 UTF-8 或標點符號將按原樣傳遞。
- 空格不是 Hash 中定義的編碼的一部分,因此您可以使用 String#join 而不必特別對待它們。
使用 Ruby 3.0.2:
def caesar_cypher phrase, key
warn "no encoding when key=#{key}" if (key % 26).zero?
letters = [*(?A..?Z), *(?a..?z)]
encoding = letters.rotate(key).zip(letters).to_h.invert
phrase.chars.map { encoding.fetch _1, _1 }.join
end
您可以通過以下一些示例驗證這是否為您提供了可重復的輸出:
# verify your mapping with key=0,
# which returns the phrase as-is
caesar_cypher "foo bar", 0
#=> "foo bar"
caesar_cypher "foo bar", 5
#=> "ktt gfw"
caesar_cypher "Et tu, Brute?", 43
#=> "vk kl, silkV?"
# use any other rotation value you like;
# you aren't limited to just 0..51
caesar_cypher "Veni, vidi, vici", 152
#=> "Raje, reZe, reYe"
# UTF-8 and punctuation (actually, anything
# not /[A-Za-z]/) will simply pass through
# unencoded since it's not defined in the
# encoding Hash
caesar_cypher "?.?.ú.", 10
#=> "?.?.ú."
編號引數的語法說明
上面的代碼應該適用于最新的 Ruby 版本,但在 2.7 之前的版本上,您可能需要_1將塊內的變數替換為以下內容:
phrase.chars.map { |char| encoding.fetch(char, char) }.join
而不是依賴編號的位置引數。我想不出還有什么會阻止此代碼在任何未過期的 Ruby 版本上運行,但如果您發現某些特定內容,請添加評論。
uj5u.com熱心網友回復:
A_ORD = 'A'.ord
def caesar_cypher(str, offset)
h = ('A'..'Z').each_with_object(Hash.new(&:last)) do |ch,h|
h[ch] = (A_ORD (ch.ord - A_ORD offset) % 26).chr
h[ch.downcase] = (h[ch].ord 32).chr
end
str.gsub(/./, h)
end
嘗試一下。
caesar_cypher("Hello world!", 4)
#=> "Lipps asvph!"
caesar_cypher("What a string!", 6)
#=> "Cngz g yzxotm!"
在執行第一個示例時,變數持有的哈希h等于
{"A"=>"E", "a"=>"e", "B"=>"F", "b"=>"f", "C"=>"G", "c"=>"g", "D"=>"H",
"d"=>"h", "E"=>"I", "e"=>"i", "F"=>"J", "f"=>"j", "G"=>"K", "g"=>"k",
"H"=>"L", "h"=>"l", "I"=>"M", "i"=>"m", "J"=>"N", "j"=>"n", "K"=>"O",
"k"=>"o", "L"=>"P", "l"=>"p", "M"=>"Q", "m"=>"q", "N"=>"R", "n"=>"r",
"O"=>"S", "o"=>"s", "P"=>"T", "p"=>"t", "Q"=>"U", "q"=>"u", "R"=>"V",
"r"=>"v", "S"=>"W", "s"=>"w", "T"=>"X", "t"=>"x", "U"=>"Y", "u"=>"y",
"V"=>"Z", "v"=>"z", "W"=>"A", "w"=>"a", "X"=>"B", "x"=>"b", "Y"=>"C",
"y"=>"c", "Z"=>"D", "z"=>"d"}
片段
Hash.new(&:last)
如果與
Hash.new { |h,k| k }
其中塊變數h是正在創建的(初始為空的)哈希并且k是一個鍵。如果定義了哈希
hash = Hash.new { |h,k| k }
然后(可能在添加鍵值對之后)如果hash沒有鍵k,則hash[k]回傳k(即字符k保持不變)。
請參閱Hash::new的形式,它接受一個塊但沒有引數。
我們可以輕松創建解密方法。
def caesar_decrypt(str, offset)
caesar_cypher(str, 26-offset)
end
offset = 4
s = caesar_cypher("Hello world!", offset)
#=> "Lipps asvph!"
caesar_decrypt(s, offset)
#=> "Hello world!"
offset = 24
s = caesar_cypher("Hello world!", offset)
#=> Fcjjm umpjb!
caesar_decrypt(s, offset)
#=> "Hello world!"
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/330623.html
下一篇:盡管條件應該阻止它,但已定義變數
