条形码的2字符校验位是否使用第一个或第二个字符?

时间:2013-09-04 16:08:33

标签: c# barcode barcode-printing

基于我对如何计算条形码的校验位的理解,即:

0) Sum the values of all the characters at odd indexes (1, 3, etc.)
1) Multiply that sum by 3
2) Sum the values of all the characters at even indexes (o, 2, etc.)
3) Combine the two sums from steps 1 and 2
4) Calculate the check digit by subtracting the modulus 10 of the combined sum from 10

因此,例如,条形码“04900000634”的总和为40 *;要获得校验和,模数(40%10)== 0,然后10 - 0 == 10.

  • 奇数字符== 7; X3 = 21;甚至字符== 19,总和为40.

由于校验位是标量值,如果校验位计算的结果是10,该怎么办?是使用“0”还是“1”?

以下是我正在使用的代码(感谢此处的一些帮助:Why does 1 + 0 + 0 + 0 + 3 == 244?);我假设上面的伪编码公式适用于条形码的长度(8个字符,12个字符等)和类型(128,EAN8,EAN12等)。

private void button1_Click(object sender, EventArgs e)
{
    string barcodeWithoutCzechSum = textBox1.Text.Trim();
    string czechSum = GetBarcodeChecksum(barcodeWithoutCzechSum);
    string barcodeWithCzechSum = string.Format("{0}{1}", barcodeWithoutCzechSum, czechSum);
    label1.Text = barcodeWithCzechSum;
}

public static string GetBarcodeChecksum(string barcode)
{
    int oddTotal = sumOddVals(barcode);
    int oddTotalTripled = oddTotal*3;
    int evenTotal = sumEvenVals(barcode);
    int finalTotal = oddTotalTripled + evenTotal;
    int czechSum = 10 - (finalTotal % 10);
    return czechSum.ToString();
}

private static int sumEvenVals(string barcode)
{
    int cumulativeVal = 0;
    for (int i = 0; i < barcode.Length; i++)
    {
        if (i%2 == 0)
        {
            cumulativeVal += Convert.ToInt16(barcode[i] - '0');
        }
    }
    return cumulativeVal;
}

private static int sumOddVals(string barcode)
{
    int cumulativeVal = 0;
    for (int i = 0; i < barcode.Length; i++)
    {
        if (i % 2 != 0)
        {
            cumulativeVal += Convert.ToInt16(barcode[i] - '0');
        }
    }
    return cumulativeVal;
}

更新

此处的计算器:http://www.gs1us.org/resources/tools/check-digit-calculator声称04900000634的校验位为6

如何到达?

更新2

http://www.gs1.org/barcodes/support/check_digit_calculator 修改我对等式/公式的最后部分的理解,其中它表示“从最接近的等于或高于10的倍数减去总和= 60-57 = 3(校验位)”

因此,在04900000634的情况下,总和为40.根据该公式,40的“最接近或等于10的倍数”为40,所以40-40 = 0,我希望是支票金额(不是6)......所以,仍然困惑......

更新3

我还没理解为什么,但是mike z的评论必须是正确的,因为当我在sumOddVals()和sumEvenVals()中反转“==”和“!=”逻辑时函数,我的结果对应于http://www.gs1us.org/resources/tools/check-digit-calculator

生成的结果

更新4

显然,基于http://en.wikipedia.org/wiki/European_Article_Number,支票数字计算背后的权力不会将第一个位置视为位置0,而是位置1.让开发人员感到困惑,经过培训可以看到第一个项目位于索引0,而不是1!

3 个答案:

答案 0 :(得分:1)

不同的条形码格式有不同的权重。您已经描述了EAN格式的格式 - 1313加权。而UPC使用3131加权方案。 ISBN-10使用完全不同的方案 - 权重不同,计算以模11进行。

我认为你使用的引用是假设数字从1开始索引而不是0.结果是你混合了奇数和偶数字符。因此总和为3 x 19 + 7 = 64,因此校验位为6而不是0.对于EAN和UPC,校验位是必须添加到总和中的值,以使数字可被10整除。

<强>更新

您对校验位算法的描述仅对某些类别的EAN条形码是准确的,因为权重是对齐的,因此最后一位数总是加权3(参见EAN Number)。因此,根据精确的EAN方案(8,12,13或14位),奇数或偶数的加权方式不同。

因此适当的权重是

0 4 9 0 0 0 0 0 6 3 4
3 1 3 1 3 1 3 1 3 1 3

总和为64,校验位为6。

答案 1 :(得分:1)

校验位始终为最后一位。

从校验位左侧的数字开始并向左移动,对每个数字求和,交替应用3和1的权重。

校验位是需要添加的数字,以产生10的倍数结果。

这适用于所有EAN / UPC代码 - UPC-E,EAN-8(除了那些从0,6或7开始的所有有效8位代码)UPC-A(12位),EAN-13 ,EAN-14(有时称为“TUN”或“Carton”代码)和SSCC(实际上是18位数,但实现为EAN128标准的一部分,人工智能为'00',误导了一些人认为他们是20位数码)

当引入UPC-E时,原始方案是[语言] [公司] [产品] [检查]。 0,6和7分配给英语,其余未分配。 [公司]和[产品]是可变长度,总共6位数;对于拥有众多产品的公司而言,公司数量较少,对于产品较少的公司而言则很长。

EAN使用了其余的数字,但指定[country] [company] [product] [check],其中country是2位数。

该系统很快耗尽了,但仍然偶尔会分配给非常小的产品 - 并且推出了在UPC-A / EAN-13之前有数字的原始产品。

UPC-A使用与UPC-E相同的模式,但丢失了对“语言”的引用。 0,6和7被分配到美国/加拿大。公司+产品扩展到10位数。

EAN-13将计划扩展到13位,国家2位,公司+产品10位,检查1位。 UPC-A通过在前导“0”前加上兼容。

通过实施13位数计划,美国公司可以跟踪这些代码中的每一个,并且不需要在已经分配了EAN-13的产品上发布UPC-As。这计划在大约8年前完成,但有些公司仍然落后。

EAN-14用于纸箱外壳。前导数字通常称为“交易单位标识符/数字”因此整个代码有时称为TUN。起初,有人试图编纂前导数字(1 = 1doz,2 = 2doz等),但很快就放弃了。大多数公司使用该数字作为包装级别(1 =单个项目的集群,2 =集群托盘,3 =托盘盒 - 取决于每个公司的偏好.9保留。使用0不是一个好主意(尽管一些公司)因为它产生与13位代码相同的校验位。我用它来代表非零售商品上的批号的EAN128代码; AI = 01; EAN-14(= EAN13,TUN = 0) ; AI = 10;间歇数目

SSCC是另一种蠕虫病毒。它们是18位数 - 第一个数字最初用作逻辑描述符,然后是国家代码,制造商代码和带有校验位的包号。最初,“3”表示“外部”托盘,“4”表示“内部”托盘,但是这不再使用,因为“内部”托盘如果被“外部”发送,则必须重新编号。 -versa。

当然,随着越来越多的国家采用该系统,2位数的国家代码已被3位数取代。

答案 2 :(得分:0)

基于此:http://www.gs1.org/barcodes/support/check_digit_calculator,条形码计算公式可以从1开始,也可以从3开始,基于条形码的最终长度是否均匀(包括校验和值)或添加。如果包括校验和在内的字符总数是偶数,则第1位数的权重为3;否则(总字数为奇数),第一位数的权重为1.在任何一种情况下,3s和1s交替,如“13131313 ......”或“31313131 ......”

但他们似乎总是以3的重量结束;所以,条码是多长时间,或者它是奇数还是偶数都无关紧要。假设最后一位数的权重为3,只需计算“向后”的值;然而,无论条形码是偶数还是奇数,也就是说,最后一个数字和与它交替的数字是偶数还是奇数都会使世界变得不同,所以必须注意。 “内部”序数以条形码中的倒数第二个字符开头,向后跳过一个; “外部”序数是最后一个,然后是其他每个。无论如何,这里是AFAIK应该用于生成和验证/验证所有条形码类型的校验位的代码:

private void button1_Click(object sender, EventArgs e)
{
    string barcodeWithoutCheckSum = textBox1.Text.Trim();
    string checkSum = GetBarcodeChecksum(barcodeWithoutCheckSum);
    string barcodeWithCheckSum = string.Format("{0}{1}", barcodeWithoutCheckSum, checkSum);
    label1.Text = barcodeWithCheckSum;
    textBox1.Focus();
}

public static string GetBarcodeChecksum(string barcode)
{
    int oddTotal;
    int oddTotalTripled;
    int evenTotal;
    // Which positions are odd or even depend on the length of the barcode, 
    // or more specifically, whether its length is odd or even, so:
    if (isStringOfEvenLen(barcode))
    {
        oddTotal = sumInsideOrdinals(barcode);
        oddTotalTripled = oddTotal * 3;
        evenTotal = sumOutsideOrdinals(barcode);
    }
    else
    {
        oddTotal = sumOutsideOrdinals(barcode);
        oddTotalTripled = oddTotal * 3;
        evenTotal = sumInsideOrdinals(barcode);
    }
    int finalTotal = oddTotalTripled + evenTotal;
    int modVal = finalTotal%10;
    int checkSum = 10 - modVal;
    if (checkSum == 10)
    {
        return "0";
    }
    return checkSum.ToString();
}

private static bool isStringOfEvenLen(string barcode)
{
    return (barcode.Length % 2 == 0);
}

// "EvenOrdinals" instead of "EvenVals" because values at index 0,2,4,etc. are seen by the 
// checkdigitmeisters as First, Third, Fifth, ... (etc.), not Zeroeth, Second, Fourth
private static int sumInsideOrdinals(string barcode)
{
    int cumulativeVal = 0;
    for (int i = barcode.Length-1; i > -1; i--)
    {
        if (i % 2 != 0)
        {
            cumulativeVal += Convert.ToInt16(barcode[i] - '0');
        }
    }
    return cumulativeVal;
}

// "OddOrdinals" instead of "OddVals" because values at index 1,3,5,etc. are seen by the 
// checkdigitmeisters as Second, Fourth, Sixth, ..., not First, Third, Fifth, ...
private static int sumOutsideOrdinals(string barcode)
{
    int cumulativeVal = 0;
    for (int i = barcode.Length - 1; i > -1; i--)
    {
        if (i % 2 == 0)
        {
            cumulativeVal += Convert.ToInt16(barcode[i] - '0');
        }
    }
    return cumulativeVal;
}

更新

使用上面的代码,可以很容易地添加一个函数来验证条形码(带有附加的checkdigit)是否有效:

private static bool isValidBarcodeWithCheckDigit(string barcodeWithCheckDigit)
{
    string barcodeSansCheckDigit = barcodeWithCheckDigit.Substring(0, barcodeWithCheckDigit.Length - 1);
    string checkDigit = barcodeWithCheckDigit.Substring(barcodeWithCheckDigit.Length - 1, 1);
    return GetBarcodeChecksum(barcodeSansCheckDigit) == checkDigit;
}