如何拆分字符串,迭代它,并输出连接的版本

时间:2016-02-23 06:04:40

标签: ruby string join split

我正在编写一种加密方法。我正在处理RewriteRule ^/wiki/Main_Page$ /wiki/Welcome_to_Our_Site [R]的代码。我写的代码如下:

caesar_cipher

当我传递一个由多个单词组成的字符串时,我收到此错误:

def caesar(string, shift = 0)
  alphabet = ("a".."z").to_a
  letters = string.split("")
  blank = []
  letters.map do |letter|
    blank << alphabet[(alphabet.index(letter) + shift) % alphabet.length]   
  end       
  puts blank.join
end

我理解block in `caesar_cipher': undefined method `+' for nil:NilClass (NoMethodError) 可以解决我的问题,如果我要创建一个类。我有一个独立的方法,除句子外,在tr的每个角度都有效。我无法将这些词分开,迭代,然后加入。任何输入都可以帮助我避免这种情况。

4 个答案:

答案 0 :(得分:2)

在使用回复中的建议后,我能够将我的代码调整为以下内容,使其适用于句子而不只是一个单词:

def caesar(string, shift=0)
alphabet = ("a".."z").to_a
    blank = string.each_char.map do |letter|
    alphabet.include?(letter) ? alphabet[(alphabet.index(letter) + shift) % alphabet.length] : letter
    end
puts blank.join
end

答案 1 :(得分:1)

错误是由于以下原因:

(alphabet.index(letter) + shift)

对于每个空格letter = " ",多个单词的情况。现在你正在做alphabet.index(letter)。由于数组alphabet没有" "元素,因此会返回nil,之后您会添加并获得apt错误:

  

未定义的方法`+'代表nil:NilClass(NoMethodError)

了解错误来源后,解决方法取决于您的算法。

答案 2 :(得分:1)

不要分手/加入单词。只需跳过加密字母表中不包含的字符:

blank = letters.map do |letter|
  if alphabet.include?(letter)
    alphabet[(alphabet.index(letter) + shift) % alphabet.length]
  else
    letter
  end
end

您会注意到上述代码没有blank << ...。这适用于each,但不适用于mapmap返回一个新数组,其中一个项目对应于原始数组中的每个项目,因此此代码只将结果数组分配给blank(这意味着无需执行{{1}首先)。

P.S。而不是使用blank = [],而是使用letters = string.split("")或更好地完全摆脱letters = string.chars并执行letters

答案 3 :(得分:1)

当您的问题已经确定时,让我建议另一种方法来进行加密,这将说明使用各种具有广泛应用的Ruby方法。我将假设要加密的字符串不包含大写字母,只有字母可以移位。

<强>代码

def caesar(str, shift = 0)
  arr = [*'a'..'z']
  mapping = arr.zip(arr.rotate(shift)).to_h
  mapping.default_proc = proc { |h,k| h[k] = k }
  str.gsub(/./, mapping)
end

示例

caesar "the die is cast.", 3
  #=> "wkh glh lv fdvw."

<强>解释

首先,对于shift = 3

arr = [*'a'..'z']
  #=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", 
  #    "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] 
mapping = arr.zip(arr.rotate(shift)).to_h
  #=> {"a"=>"d", "b"=>"e", "c"=>"f", "d"=>"g", "e"=>"h", "f"=>"i", "g"=>"j",
  #    "h"=>"k", "i"=>"l", "j"=>"m", "k"=>"n", "l"=>"o", "m"=>"p", "n"=>"q",
  #    "o"=>"r", "p"=>"s", "q"=>"t", "r"=>"u", "s"=>"v", "t"=>"w", "u"=>"x",
  #    "v"=>"y", "w"=>"z", "x"=>"a", "y"=>"b", "z"=>"c"}

接下来,我们使用Hash#default_proc=

为此哈希添加默认proc
mapping.default_proc = proc { |h,k| h[k] = k }
  # => #<Proc:0x007f8ec8b132b8@(irb):1241> 

如果mapping[k]没有密钥k,这会导致mapping返回k。 (没有更多。)例如,

mapping['a'] #=> 'd'
mapping['4'] #=> '4'
mapping['$'] #=> '$'
mapping[' '] #=> ' '

我认为未编码的信息是凯撒最喜欢的表达方式之一:

str = "the die is cast."

我们使用String#gsub的形式,使用哈希来获取替换值。我们希望考虑替换每个字符,我们需要匹配正则表达式/./

str.gsub(/./, mapping)
  #=> "wkh glh lv fdvw."

如果我们没有将默认proc附加到哈希,我们就会得到 "wkhglhlvfdvw"