2014-09-30 84 views
0

我正在尝试编写凯撒密码,但我试图解决映射循环中使用的正则表达式问题。我的代码是:正则表达式和映射问题

class Cipher 

    attr_reader :string 
    attr_reader :factor 

    def initialize(string, factor) 
    @string = string 
    @factor = factor 
    end 

    def factored_ascii 
    @string.chars.map do |letter| 
     value = letter.ord + (@factor % 26) 

     if letter =~ /[a-z]/ && value > 122 
     value = (value % 122) + 96 

     elsif letter =~ /[A-Z]/ && value > 90 
     value = (value % 90) + 64 

     elsif letter =~ /[^A-Za-z]/ 
     value = letter.ord 
     end 
    end 
    end 
end 

当字符串参数“什么的字符串”,它只有在正确的第一W字符和空格字符操作的对象调用factored_ascii,设置其他元素尼尔斯。

[66, nil, nil, nil, 32, nil, 32, nil, nil, nil, nil, nil, nil] 

我很可能做一些相当愚蠢的事情。你能否帮助启发我,并且为了解决这个问题而节省更多的时间?

+0

我无法理解你想要的结果,但我可以解释你为什么得到nils。你的问题在if语句中:它没有捕获所有其他情况的'else'块。结果你的迭代对大多数字符返回nil。注意最后一个正则表达式'/ [^ A-Za-z] /'有'^'这意味着行首! – gotva 2014-09-30 12:48:05

+1

@gotva'^'里面的[]'表示否定不起动 – vks 2014-09-30 13:04:18

+0

哦,你说得对。但我认为这并没有改变这种情况。它看起来像大多数字母不被条件内的条件捕获。 – gotva 2014-09-30 13:08:07

回答

1

map将值映射到由块返回的值。除非显式返回一个值,否则块的返回值是最后执行的语句的值。在你的情况下,这是if语句。如果没有符合条件,则返回nil

例如:

x = [1,2,3,4] 
x.map do |y| 
    if y % 2 == 0 
    y 
    end 
end 
# [nil, 2, nil, 4] 

查看所有不符合条件的值怎么弄nil?要修复你的代码,只需在if语句后面加上value,这可以确保它始终是返回值。

1

@Max已经回答了你的问题,但你可能要考虑不同的书写方法:

def factored_ascii 
    @string.chars.map do |letter| 
    value = letter.ord + (@factor % 26) 
    case(letter)    
    when /[a-z]/ && value > 122 
     (value % 122) + 96 
    when /[A-Z]/ && value > 90 
     (value % 90) + 64 
    when /[^A-Za-z]/ 
     letter.ord 
    else 
     value 
    end 
    end 
end 

@string = "aZr$" 
@factor = 0 
factored_ascii #=> [97, 90, 114, 36] 

这工作,因为case语句使用===(这里Regexp#===)的比较(例如,when /[a-z]/相当于letter =~ /[a-z]/)。