计算 UPC-A 条形码的校验位

本文关键字:校验 条形码 UPC-A 计算 | 更新日期: 2023-09-27 18:36:43

我目前正在VS2010中处理Windows表单,该表单应该为新零件号创建UPC-A并将它们存储在数据库中。到目前为止,我仍在尝试将这些碎片放在一起,并且在计算校验位时遇到问题。我想出了以下两种方案:

场景 1:按照我们目前在 Excel 中的方式进行计算:

string value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]["UPCNumber"].ToString();
string manCode = value.Substring(1, 5);
string prodCode = value.Substring(7, 5);
int first = Math.Abs(Convert.ToInt32(value));
while (first >= 10)
first /= 10;
int chkDigitSubtotal;
string UPCNumber = first + manCode + prodCode;
chkDigitSubtotal = Convert.ToInt32((UPCNumber.Substring(1, 1)) + (UPCNumber.Substring(3, 1)) + 
(UPCNumber.Substring(5, 1)) + (UPCNumber.Substring(7, 1)) + (UPCNumber.Substring(9, 1)) + 
(UPCNumber.Substring(11, 1)));
chkDigitSubtotal = (3 * chkDigitSubtotal) + Convert.ToInt32((UPCNumber.Substring(2, 1)) + 
(UPCNumber.Substring(4, 1)) + (UPCNumber.Substring(6, 1)) + (UPCNumber.Substring(8, 1)) + 
(UPCNumber.Substring(10, 1)));
 string chkDigit = ((300 - chkDigitSubtotal).ToString()).Substring(12, 1);

当我运行此代码时,我收到错误"值对于 Int32 来说太大或太小"。我不明白为什么,因为"值"是一个有 12 个字符的varchar(它们都是数字)。

场景 2:我发现一个代码在网上被截取。此代码有效,但给了我错误的校验位。我正在使用我们使用您的 Excel 工作表计算的 UPC:

string value = "606891001678"; //valid UPC with check digit
string UPCBody = value.Substring(0, 11);
int sum = 0;
bool odd = true;
for (int i = value.Length - 1; i >= 0; i--)
{
    if (odd == true)
    {
        int tSum = Convert.ToInt32(value[i].ToString()) * 2;
        if (tSum >= 10)
        {
            string tData = tSum.ToString();
            tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
        }
        sum += tSum;
    }
    else
        sum += Convert.ToInt32(value[i].ToString());
    odd = !odd;
}
int result = (((sum / 10)+1) *10) - sum;
result = result % 10;
MessageBox.Show(UPCBody + " & " + result);

在此示例中,校验位显然应该是 8,但它返回 2。我几乎整天都在研究这个问题,可以使用一些建议。为什么我在第一个场景中出现错误,为什么在第二个场景中得到的校验位与应有的校验位不同?

提前感谢您的帮助!

克里斯

编辑:

我删除了之前的两次编辑,因为代码在某种意义上是有缺陷的,因为我没有得到正确的结果。我发现我们使用杜鹃花条形码,他们有自己的方法来计算校验位(见ChkDigitSubtotal)。因此,下面的代码有效,并为我的方案提供了正确的校验位。我认为此代码将适用于所有 UPC-A 计算的 chkDigitSubtotal。感谢哈里森的出色指导和足智多谋的回答!

string value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]
["UPCNumber"].ToString();
long chkDigitOdd;
long chkDigitEven;
long chkDigitSubtotal;
string UPCNumber = value.Substring(0, 11);
chkDigitOdd = Convert.ToInt64(UPCNumber.Substring(0, 1)) +
Convert.ToInt64(UPCNumber.Substring(2, 1)) + Convert.ToInt64(UPCNumber.Substring(4, 1)) 
+ Convert.ToInt64(UPCNumber.Substring(6, 1)) + Convert.ToInt64(UPCNumber.Substring(8, 
1)) + Convert.ToInt64(UPCNumber.Substring(10, 1));
chkDigitOdd = (3 * chkDigitOdd);
chkDigitEven = Convert.ToInt64(UPCNumber.Substring(1, 1)) + 
Convert.ToInt64(UPCNumber.Substring(3, 1)) + Convert.ToInt64(UPCNumber.Substring(5, 1)) 
+ Convert.ToInt64(UPCNumber.Substring(7, 1)) + Convert.ToInt64(UPCNumber.Substring(9, 
1));
chkDigitSubtotal = (300-(chkDigitEven + chkDigitOdd));
string chkDigit = chkDigitSubtotal.ToString();
chkDigit = chkDigit.Substring(chkDigit.Length - 1, 1);

计算 UPC-A 条形码的校验位

根据我在维基百科上阅读的内容,您在第一个示例中计算不正确。

    String.Substring + String.Subtring 或 "1"
  • + "1" = "11"。 你是寻找 1+1=2。 您需要先将每个子字符串转换为 int到添加。

+ 运算符(C# 参考)

二进制 + 运算符是为数字和字符串类型预定义的。为 数值类型 + 计算其两个操作数的总和。当一个或 两个操作数都是字符串类型,+ 连接字符串 操作数的表示形式。

  • String.Substring 从 0 开始,因此您缺少 偶数的String.Substring(0,1)
字符串

.子字符串方法

startIndex:子字符串的起始字符位置 在这种情况下。

    校验位字符串尝试获取少于 12 位的
  • 字符串的第 12 位数字。 此外,这不是链接中显示的计算。 它正在寻找该数字的 10 - mod 10。 这也发生在您更新的编辑

string chkDigit = ((300 - chkDigitSubtotal).ToString()).Substring(12, 1);

您正在尝试从第 12 个从 0 开始的字符或长度为 1 的第 13 个字符中获取Substring。 但是,chkDigitSubtotal的值不会那么大/长。

至于你的错误,正如金龙在他的回答中所说,你正在将一个 12 个字符的字符串转换为一个数字,这不适合Int32,你应该使用长。

int first = Math.Abs(Convert.ToInt32(value));

转到

long first = Math.Abs(Convert.ToInt64(value));

我会首先检查您的计算在前面的步骤中是否合乎逻辑地运行。

更新

在您的编辑 2 中,看起来您的最后一行% operator周围的变量颠倒了。 你想把 109 的余数除以 10(即 9),而你的代码取 10 的余数除以 109(即 0),所以改变。

chkDigitSubtotal = 10 - (10 % (chkDigitEven + chkDigitOdd));

chkDigitSubtotal = 10 - ((chkDigitEven + chkDigitOdd) % 10);

现在 10 - 9 = 1,这是您的校验位。

如果value是一个 12 位长的字符串,那么它太大而无法放入int。 请改用long