1

我正在尝试在 Ruby 中为 FedEx 跟踪号码构建校验位计算。

以下是校验位计算的信息和步骤:

  • 数字位置从右到左标记。
  • 数字 1 是校验字符。
  • 不使用数字 16 到 22。

脚步:

  1. 从位置 2 开始,将偶数位置的值相加
  2. 将步骤的结果乘以 3。
  3. 从位置 3 开始,将奇数位置的值相加。请记住 - 位置 1 是您要计算的校验位。
  4. 将步骤二的结果与步骤三的结果相加。
  5. 确定与第四步中的数字相加时得到 10 倍数的最小数字。这是校验位。

以下是流程示例(由 FedEx 提供): 在此处输入图像描述

那么,我如何在 Ruby 中实现它呢?

4

2 回答 2

6

当你有你的数字作为字符串(或者如果你有你的数字作为整数,就#to_s在它上面并获取字符串),然后你可以简单地从那里提取数字:

number_string[idx].to_i

或者如果你使用 Ruby 1.8

number_string[idx..idx].to_i

#to_i就是把它转成整数,这样就可以加给别人了。然后继续执行提供的步骤来计算您的号码。

实现它所需要做的就是正确地将指令中提供的位置映射到idx数字字符串表示中的索引位置。只需在纸上计算 head 或在 Ruby 中使用负 idx(从字符串末尾开始计算)。

编辑

解决方案可能是这样的:

bar_code_data = "961102098765431234567C"
digits_with_position = bar_code_data.reverse[1..14].split(//).map(&:to_i).zip(2..1/0.0)

如下:

  • reverse- 反转字符串,所以现在我们可以从左到右计数而不是反转
  • [1..14]- 选择我们感兴趣的字符子串(Ruby 从 0 开始计数)
  • split(//)- 将一个字符串拆分为长度为 1 个字符的子字符串,换句话说 - 单独的数字
  • map(&:to_i)- 在数组的每个元素上调用#to_i,换句话说,转换为整数
  • zip(2..1/0.0)- 为每个元素添加从 2 到 Infinity 的位置

现在我们应该有这样的东西:

[[7, 2], [6, 3], [5, 4], [4, 5], [3, 6], [2, 7], [1, 8], [3, 9], [ 4, 10], [5, 11], [6, 12], [7, 13], [8, 14], [9, 15]]

sum = digits_with_position.map{|i| i[0] * (i[1].even? ? 3 : 1)}.reduce(+:)

我们在算法上几乎没有改变,你应该不难理解:

代替:

sum = (in[2] + in[4] + in[6] + ...)*3 + (in[3] + in[5] + in[7] + ...)

我们创造:

sum = in[2]*3 + in[3]*1 + in[4]*3 + in[5]*1 + in[6]*3 + in[7]*1 + ...

这是相同的结果,但操作顺序发生了变化。

还:

  • map {|i| ... }- 映射列表的每个值,在我们的例子中 i 是元组,一对 [digit,pos]
  • i[1].even?- 检查位置是否是偶数
  • i[1].even? ? 3 : 1- 对于偶数位置使用 3,对于相反(奇数)仅使用 1
  • reduce(:+)- 使用 + 操作将结果数组减少为单个值(添加所有结果)

现在有趣的部分:-)

check_code = 10 - (sum % 10)
  • sum % 10- 和值的模块 10,返回除以 10 的提示,在我们的例子中是最后一位
  • 10 - (sum % 10)- 补到最接近的不小于 10 的倍数

描述有错误,因为如果你得到 130 作为结果,那么 10 的下一个更大的倍数是 140 并且差是 10,这对于数字来说不是正确的结果(它可能应该是 0)。

其他更快的解决方案是这样的(展开所有循环,只需对所有内容进行硬编码):

d = "961102098765431234567C".split(//) # avoid having to use [-2..-2] in Ruby 1.8
sum_even = d[-2].to_i + d[-4].to_i + d[-6].to_i + d[-8].to_i + d[-10].to_i + d[-12].to_i + d[-14].to_i
sum_odd = d[-3].to_i + d[-5].to_i + d[-7].to_i + d[-9].to_i + d[-11].to_i + d[-13].to_i + d[-15].to_i
sum = sum_even * 3 + sum_odd
check_code = 10 - sum % 10

这只是简单的解决方案,不值得解释,除非有人要求

于 2011-08-29T13:02:26.383 回答
0

将您的号码传递给以下方法,它将返回附加校验和数字的号码。参考来自:https ://www.gs1.org/services/how-calculate-check-digit-manually

def add_check_digit(code_value) 
   sum = 0
   code_value.to_s.split(//).each_with_index{|i,index| sum = sum + (i[0].to_i * ((index+1).even? ? 3 : 1))}
   check_digit = sum.zero? ? 0 : (10-(sum % 10))
   return (code_value.to_s.split(//)<<check_digit).join("")
end
于 2021-05-26T18:04:32.017 回答