C# 我需要什么代码来计算任何条形码的校验和,以及验证/验证现有校验和?

C# 我需要什么代码来计算任何条形码的校验和,以及验证/验证现有校验和?,c#,barcode,barcode-scanner,checksum,C#,Barcode,Barcode Scanner,Checksum,有许多条形码类型和大小(长度)。是否有一套通用算法可用于计算任何条形码的校验和?条形码虽然长度不同,语义不同,但在生成校验和时仍遵循一些基本规则。下面的代码可以复制到一个小的util中进行测试(或者简单地使用非事件处理代码): 要使用此功能,请创建WinForms应用程序,并在其上删除以下控件: 0) A button named button1; give it text something like "Calculate barcode and append it to label belo

有许多条形码类型和大小(长度)。是否有一套通用算法可用于计算任何条形码的校验和?

条形码虽然长度不同,语义不同,但在生成校验和时仍遵循一些基本规则。下面的代码可以复制到一个小的util中进行测试(或者简单地使用非事件处理代码):

要使用此功能,请创建WinForms应用程序,并在其上删除以下控件:

0) A button named button1; give it text something like "Calculate barcode and append it to label below", if desired
1) A button named button2; give it text something like "Valid barcode + czech digit", if desired
2) A label named label1, which displays the result of clicking button1
3) A textBox named textBox1, wherein you enter a raw barcode value (sans check digit) prior to clicking button1 OR enter a full barcode value (with check digit) prior to clicking button2

// "Calculate check sum" handler
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();
}

// Verify/validate existing checksum handler
private void button2_Click(object sender, EventArgs e)
{
    string bcVal = textBox1.Text.Trim();
    bool validCheckDigit = isValidBarcodeWithCheckDigit(bcVal);
    MessageBox.Show(validCheckDigit ? string.Format("{0} is valid", bcVal) : string.Format("{0} invalid", bcVal));
}

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;
}

private static bool isValidBarcodeWithCheckDigit(string barcodeWithCheckDigit)
{
    string barcodeSansCheckDigit = barcodeWithCheckDigit.Substring(0, barcodeWithCheckDigit.Length - 1);
    string checkDigit = barcodeWithCheckDigit.Substring(barcodeWithCheckDigit.Length - 1, 1);
    //MessageBox.Show(string.Format("raw barcode portion is {0}", barcodeSansCheckDigit));
    //MessageBox.Show(string.Format("check portion is {0}", checkDigit));
    return GetBarcodeChecksum(barcodeSansCheckDigit) == checkDigit;
}

是的,有一种非常常见的校验和计算器算法。各种条形码(和其他数字输入方案)使用它们来验证扫描仪(或人员)是否正确输入了所有数字。最早的例子之一,也是最普遍理解的校验和算法是Luhn算法,它以在信用卡上使用而闻名;但它有许多不同之处。然而,在他们的核心,大多数使用相同的算法

通用算法使用与数字位置相对应的权重数组、模除数和指示“产品添加”或“产品数字添加”方案的标志

伪码 共同计划 校验数字方案在各个行业中普遍使用,条形码生产和验证只是其中之一。以下是可用于此算法的一些常见校验位方案的列表:

  • UPC-A条码:权重为{3,1,3,1,3,1,1,3,1,1,3,1}的12位数字,除数为10,productDigitAdd值为假
  • EAN-13条码:权重为{1,3,1,3,1,3,1,3,1,1,3,3,1},除数为10,productDigitAdd值为假
  • 代码128条形码:数字是条形码的代码值,而不是条形码包含的值(例如,在模式A和B中,条形码符号值65表示ASCII字母“A”,但在模式C中是一对数字“33”);权重是{1,2,3,4,5…通过条形码符号总数1},其中1是右端的校验位权重;除数是103;并且productDigitAdd值为false
  • POSTNET条形码:权重为{1,1,1,1,1,1,1,1,1},除数为10,productDigitAdd值为false
  • 16位信用卡:权重是由16位数字组成的数组,{2,1,2,1…2,1},除数是10,productDigitAdd值为真。这是卢恩算法
  • ISBN(书号):权重为{10,9,8,7,6,5,4,3,2,1},除数为11,productDigitAdd字段为false
  • 路由中转号(在银行支票上):权重为{3,7,1,3,7,1,3,7,1},除数为10,ProductDigitAddd字段为false
验证 要使用此算法验证条形码,只需将其输出值与零进行比较。非零值表示故障

一个常见的错误是试图隔离校验位,然后将例程的输出与隔离的校验位进行比较。简单地将校验位包含在整个循环中,然后将输出与零进行比较,更简单、更安全。然后,该算法继续适用于嵌入条形码右端以外位置的校验位,或校验位具有非一个权重的位置

一代 您还可以使用相同的算法来计算校验位,就像生成新条形码时一样。在您的输入数据中,其中一个数字将保留为检查数字的位置。这通常是,但并不总是,最右边的数字。将输入数字数组的位置设置为零。像验证输入数据一样调用算法,然后从模除数中减去算法的输出。用减去的输出替换输入数字数组中的零占位符

特例 Luhn算法通常以非常非正式的方式实现。一种常见的描述方法是“每隔两位数,然后将总和的位数相加,最后一位数必须是校验位数”。这一方法简单地适用于16位数的卡,但可能导致代码不灵活,通常使用case语句来处理不同长度的卡号等

ISBN数字(和其他数字)使用11的除数,但这会产生一个“10”作为输出检查数字。两位数的值不适合保留为一位数的条形码位置。ISBN规范规定,“10应替换为字母‘X’”。我遇到的其他方案只是将任何产生两位数校验位数结果的数字作为不可能的数字丢弃

对于此类或其他使用非数值的方案,例如在美国和加拿大销售的汽车上,一种可靠的方法是将此例程从接受“字符串”作为输入数据改为接受输入值数组。然后在此例程之前和之后对数组执行转换步骤,以将给定符号映射到必要的值。通常我会保留这个例程的一个版本,专门用于接受字符串类型作为输入,因为大多数程序都将条形码作为字符串处理

我遇到过旧的校验位方案,它在权重数组中包含负值。它们从总和中减去,而不是相加,但在其他方面,一切都是一样的

一种非常常见的优化方法,尤其是在嵌入式设备(如条形码扫描仪)中,是接受一个比位数短的权重数组,并将其向左扩展到与位数相同的位置。这样,所有UPC和EAN方案,包括UPC-A、UPC-E、EAN-8和EAN-13,都与一个公共例程匹配。权重为{3,1},除数为10,PDA为假。扩展权重必须通过将最右边的权重数字锚定到最右边的inputData数字来完成,因此31的权重变为

         <-31
1313131313131
9780321146533

在第二篇文章中,可以在这里找到三种不同的计算条形码的方法(一种是ab
         <-31
1313131313131
9780321146533