Luhn算法 - 对于虚假信用卡返回True

时间:2013-09-25 17:58:08

标签: ruby luhn

我的代码有点问题,看看信用卡号码是否符合Luhn算法。当信用卡可被10整除时,代码返回true,但当CC数不能被10整除时,代码也返回true。我打印出最后的总和,以确保数字实际上是加到sum变量,并且它们似乎是..下面是我的代码。我知道它可以更干净,但在这个阶段我希望看到它先工作。

def check_card

   c_num= []

   sum=0

   s_numbers=@card_numbers.to_s.reverse.split("")

   s_numbers.each_slice(2) do |x| 
   c_num << (x.last.to_s.to_i*2)
   c_num << (x.first.to_s.to_i)
     end

  c_num.each do |num|
    if num.to_i > 9
      sum+= (num.to_i % 10)+1
    else 
      sum += num.to_i
    end
  end

sum % 10==0 

end

以下是它的调用方式:

it 'returns false for a bad card' do
  card = CreditCard.new(4408041234567892)
  card.check_card.should eq false
end

4 个答案:

答案 0 :(得分:1)

现在又出现了另一个答案,我将提供建议的编码。这不能回答你的问题,但我认为它可能会引起人们的兴趣并且不能很好地将它放在评论中,因为格式限制。

def valid?(card)
  return false unless card  =~ /^\d+$/ # Ensure card contains only digits
  arr = card.split('').reverse.each_with_index.map {|d, index| (index.odd? ? 2*(d.to_i) : d.to_i)}
  (arr.join.split('').inject(0) {|tot, d| tot + d.to_i}) % 10 == 0
end 

valid?("1234567890123456") => false

答案 1 :(得分:0)

这是您的代码,经过评论和调整,表现得像wikipedia description

def check_card(str) #creditcardnumber as argument

   c_num = []

   sum = 0

   s_numbers = str.split("") #no reversing. str.split("").map(&:to_i) would save a lot of to_i's later on...
   checksum = s_numbers.pop.to_i #chop off last digit, store as checksum

   s_numbers.each_slice(2) do |x| 
     c_num << (x.last.to_s.to_i*2)
     c_num << (x.first.to_s.to_i)
   end

  c_num.each do |num|
    if num.to_i > 9
      sum+= (num.to_i % 10)+1
    else 
      sum += num.to_i
    end
  end

  (sum * 9) % 10 == checksum 

end

p check_card("79927398713") #=> true

答案 2 :(得分:0)

您似乎将测试的输出与check_card方法的输出混淆。您已确认sum == 69,因此sum % 10 == 0应返回false(除非Ruby的数学运算被破坏),因此您的check_card方法也应返回false - 添加测试块中行puts card.check_card之后(但在下一行之前)的行card = CreditCard.new(4408041234567892)以显示返回的值。

下一行card.check_card.should eq false断言返回的值“应该等于”false - 也就是说,check_card的{​​{1}}值为false {1}},如果是这样,将返回@card_numbers。我怀疑您看到测试出现true并认为该方法返回的值不正确true

在没有看到测试结果的情况下,这当然只是猜测。但是,您的代码似乎是正确的,对我来说,给出了正确的结果。

答案 3 :(得分:0)

发布我的答案,因为我觉得它很干净:

def valid?(card_number)
  return false unless card_number !~ /\D/

  card_numbers = card_number.reverse.split("").map(&:to_i)
  sum = 0
  card_numbers.each_with_index do |num, i|
    if i.even?
      sum += num
    else
      sum += (num *= 2) > 9 ? num.divmod(10).inject(:+) : num
    end
  end
  sum % 10 == 0
end