我需要一个C#.NET函数来评估键入或扫描的条形码是否有效Global Trade Item Number(UPC或EAN)。
条形码编号的最后一位是计算机校验位,确保条形码正确合成。 GTIN Check Digit Calculator
答案 0 :(得分:22)
public static bool IsValidGtin(string code)
{
if (code != (new Regex("[^0-9]")).Replace(code, ""))
{
// is not numeric
return false;
}
// pad with zeros to lengthen to 14 digits
switch (code.Length)
{
case 8:
code = "000000" + code;
break;
case 12:
code = "00" + code;
break;
case 13:
code = "0" + code;
break;
case 14:
break;
default:
// wrong number of digits
return false;
}
// calculate check digit
int[] a = new int[13];
a[0] = int.Parse(code[0].ToString()) * 3;
a[1] = int.Parse(code[1].ToString());
a[2] = int.Parse(code[2].ToString()) * 3;
a[3] = int.Parse(code[3].ToString());
a[4] = int.Parse(code[4].ToString()) * 3;
a[5] = int.Parse(code[5].ToString());
a[6] = int.Parse(code[6].ToString()) * 3;
a[7] = int.Parse(code[7].ToString());
a[8] = int.Parse(code[8].ToString()) * 3;
a[9] = int.Parse(code[9].ToString());
a[10] = int.Parse(code[10].ToString()) * 3;
a[11] = int.Parse(code[11].ToString());
a[12] = int.Parse(code[12].ToString()) * 3;
int sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + a[11] + a[12];
int check = (10 - (sum % 10)) % 10;
// evaluate check digit
int last = int.Parse(code[13].ToString());
return check == last;
}
答案 1 :(得分:17)
GS1 US发布GTIN的校验位计算算法 PDF文档(删除了不断变化的链接)。
以下代码使用linq检查GTIN条形码的最后一位数:GTIN-8,GTIN-12(UPC),GTIN-13(EAN)和GTIN-14(ITF-14)。
private static Regex _gtinRegex = new System.Text.RegularExpressions.Regex("^(\\d{8}|\\d{12,14})$");
public static bool IsValidGtin(string code)
{
if (!(_gtinRegex.IsMatch(code))) return false; // check if all digits and with 8, 12, 13 or 14 digits
code = code.PadLeft(14, '0'); // stuff zeros at start to garantee 14 digits
int[] mult = Enumerable.Range(0, 13).Select(i => ((int)(code[i] - '0')) * ((i % 2 == 0) ? 3 : 1)).ToArray(); // STEP 1: without check digit, "Multiply value of each position" by 3 or 1
int sum = mult.Sum(); // STEP 2: "Add results together to create sum"
return (10 - (sum % 10)) % 10 == int.Parse(code[13].ToString()); // STEP 3 Equivalent to "Subtract the sum from the nearest equal or higher multiple of ten = CHECK DIGIT"
}
答案 2 :(得分:12)
上述解决方案计算校验位并将其与给定数字进行比较,忽略了它的设计以更简单的方式验证的事实。
基于卢西亚诺的回答:
private static Regex _gtinRegex = new Regex("^(\\d{8}|\\d{12,14})$");
public static bool IsValidGtin(string code)
{
if (!(_gtinRegex.IsMatch(code))) return false;
code = code.PadLeft(14, '0');
int sum = code.Select((c,i) => (c - '0') * ((i % 2 == 0) ? 3 : 1)).Sum();
return (sum % 10) == 0;
}
答案 3 :(得分:5)
可变长度EAN
public static bool IsValidEan13(string eanBarcode)
{
return IsValidEan(eanBarcode, 13);
}
public static bool IsValidEan12(string eanBarcode)
{
return IsValidEan(eanBarcode, 12);
}
public static bool IsValidEan14(string eanBarcode)
{
return IsValidEan(eanBarcode, 14);
}
public static bool IsValidEan8(string eanBarcode)
{
return IsValidEan(eanBarcode, 8);
}
private static bool IsValidEan(string eanBarcode, int length)
{
if (eanBarcode.Length != length) return false;
var allDigits = eanBarcode.Select(c => int.Parse(c.ToString(CultureInfo.InvariantCulture))).ToArray();
var s = length%2 == 0 ? 3 : 1;
var s2 = s == 3 ? 1 : 3;
return allDigits.Last() == (10 - (allDigits.Take(length-1).Select((c, ci) => c*(ci%2 == 0 ? s : s2)).Sum()%10))%10;
}
[Test]
[TestCaseSource("Ean_13_TestCases")]
public void Check_Ean13_Is_Valid(string ean, bool isValid)
{
BlinkBuilder.IsValidEan13(ean).Should().Be(isValid);
}
private static IEnumerable<object[]> Ean_13_TestCases()
{
yield return new object[] { "9781118143308", true };
yield return new object[] { "978111814330", false };
yield return new object[] { "97811181433081", false };
yield return new object[] { "5017188883399", true };
}
[Test]
[TestCaseSource("Ean_8_TestCases")]
public void Check_Ean8_Is_Valid(string ean, bool isValid)
{
BlinkBuilder.IsValidEan8(ean).Should().Be(isValid);
}
private static IEnumerable<object[]> Ean_8_TestCases()
{
yield return new object[] { "12345670", true };
yield return new object[] { "12345679", false };
yield return new object[] { "55432214", true };
yield return new object[] { "55432213", false };
yield return new object[] { "55432215", false };
}
修改强>
我正在构建此代码的项目现已启动并运行 - 它是全面的条形码数据库和工具集的一部分 - 并且包括批量条形码验证器(非注册用户批量为100,注册为10,000) - { {3}}
答案 4 :(得分:1)
/// <summary>
/// Validates a GTIN (UPC/EAN) using the terminating check digit
/// </summary>
/// <param name="code">the string representing the GTIN</param>
/// <returns>True if the check digit matches, false if the code is not
/// parsable as a GTIN or the check digit does not match</returns>
public static bool IsValidGtin(string code)
{
if (string.IsNullOrWhiteSpace(code))
return false;
if (code.Length != 8 && code.Length != 12 && code.Length != 13
&& code.Length != 14)
// wrong number of digits
return false;
int sum = 0;
for (int i = 0; i < code.Length - 1 /* do not include check char */; i++)
{
if (!char.IsNumber(code[i]))
return false;
var cchari = (int)char.GetNumericValue(code[i]);
// even (from the right) characters get multiplied by 3
// add the length to align right
if ((code.Length + i) % 2 == 0)
sum += cchari * 3;
else
sum += cchari;
}
// validate check char
char checkChar = code[code.Length - 1];
if (!char.IsNumber(checkChar))
return false;
int checkChari = (int)char.GetNumericValue(checkChar);
return checkChari == (10 - (sum % 10)) % 10;
}
测试用例:
[TestMethod()]
public void IsValidGtinTest_Valid()
{
string[] valid = new[] {
"085126880552",
"0085126880552",
"00085126880552",
"0786936226355",
"0719852136552"
};
foreach (var upc in valid)
Assert.IsTrue(IdentifierUtilities.IsValidGtin(upc), upc);
}
[TestMethod()]
public void IsValidGtinTest_Invalid()
{
string[] invalid = new[] {
"0058126880552",
"58126880552",
"0786936223655",
"0719853136552",
"",
"00",
null,
"123456789123456789123456789",
"1111111111111"
};
foreach (var upc in invalid)
Assert.IsFalse(IdentifierUtilities.IsValidGtin(upc), upc);
}
答案 5 :(得分:1)
private bool ValidateCheckDigit()
{
Int32 _num = 0;
Int32 _checkdigit = 0;
for (int i = 0; i < CurrentUpcInfo.UpcCode.Length; i++)
{
if (i % 2 == 0)
{
_num += (3 * Convert.ToInt32(CurrentUpcInfo.UpcCode.Substring(i, 1)));
}
else
{
_num += Convert.ToInt32(CurrentUpcInfo.UpcCode.Substring(i, 1));
}
}
_num = Math.Abs(_num) + 10; // in case num is a zero
_checkdigit = (10 - (_num % 10)) % 10;
if (Convert.ToInt32(CurrentUpcInfo.Checkdigit) == _checkdigit)
return true;
return false;
}
答案 6 :(得分:1)
我有类似的问题,谷歌把我带到了这个页面。 我需要为标签生成程序计算大量条形码的校验位。我首先开始修改Luciano Carvalho的上述答案,但我有点好奇将字符串转换为字符串转换为int。我怀疑我可能会稍微改善一下表现。
请注意,此功能之外的验证正在进行。由于我生成了大量的条形码,因此该功能的构建速度更快。
int CalculateCheckDigit(ulong label)
{
int sum = 0;
bool isEven=true;
while(label>0)
{
if(isEven)
sum += (int)(label % 10) * 3;
else
sum += (int)(label % 10) * 1;
isEven = !isEven;
label /= 10;
}
return (10 - (sum % 10)) % 10;
}
答案 7 :(得分:1)
我找到了这个Nuget软件包:https://www.nuget.org/packages/ProductCodeValidator/
github中的代码为:https://github.com/ThomasPe/ProductCodeValidator。
这里是使用方法:
using ProductCodeValidator;
bool IsValidEAN(string EAN)
{
return EanValidator.IsValidEan(testEan));
}
答案 8 :(得分:0)
我知道问题出在.net / C#的上下文中。尽管如此,我还是在这个页面上找到了同样问题的答案,但是在Groovy的背景下
由于我实际上成功地使用了本页面上的信息来解答我自己的问题,我想我会分享结果。
特别是AlexDev,Zack Peterson和Mitch的答案对我有帮助。
/*
Check digit calculation is based on modulus 10 with digits in an odd
position (from right to left) being weighted 1 and even position digits
being weighted 3.
For further information on EAN-13 see:
Wikipedia - European Article Number: http://en.wikipedia.org/wiki/International_Article_Number_%28EAN%29
Implementation based on http://stackoverflow.com/questions/10143547/how-do-i-validate-a-upc-or-ean-code
Tests can be found there too
*/
boolean isValidEan(String code){
returnValue = false
if (code ==~ /\d{8}|\d{12,14}/){ //Matches if String code contains 8, 12, 13 or 14 digits
assert [8,12,13,14].contains(code.size())
code = code.padLeft(14, '0')
assert code.size() == 14
int sum = 0
code.eachWithIndex{ c, i ->
sum += c.toInteger() * ((i % 2 == 0) ? 3 : 1)
}
returnValue = sum % 10 == 0
}
return returnValue
}
答案 9 :(得分:0)
如果有人需要 AlexDev 答案的 javascript 版本,这里是。我注意到 AlexDev 的答案也适用于 ITF 条形码,而其他一些答案则不适用。
function isValidGtin(barcode) {
var code = "00000" + barcode;
code = code.substring(code.length - 14);
var sum = 0;
for (var i = 0; i < code.length; i++) {
sum += code[i] * ((i % 2 == 0) ? 3 : 1);
}
return (sum % 10) == 0;
}
答案 10 :(得分:0)
我今天花了一些时间来全面支持 GTIN-8、GTIN-12、GTIN-13 和 GTIN-14 的校验和计算。大多数算法示例仅支持 GTIN-13 或很难看。
这个怎么样?
public static char CalculateCheckSumDigit(string code)
{
// https://www.gs1.org/services/how-calculate-check-digit-manually
var reversed = code.Reverse().Skip(1);
int sum = 0;
int multiplier = 3;
foreach(char c in reversed)
{
if (multiplier == 3)
{
sum += (c - 0x30) * multiplier;
multiplier = 1;
}
else
{
sum += (c - 0x30) * multiplier;
multiplier = 3;
}
}
int closestTenth = (sum + 9) / 10 * 10;
return (char)((closestTenth - sum) + 0x30);
}
答案 11 :(得分:0)
我还需要验证大量的 EAN-13 并在我搜索时发现了这个问题。我不喜欢投票最多的答案的样子。处理大型数据集时可能分配的字符串过多。与仅验证每个字符是否为数字相比,正则表达式也很慢。
在我的 8851 个 EAN-13 数字数据集上运行最高投票问题中使用的验证逻辑需要 47 毫秒,而我自己的实现只需要 2 毫秒。 这里的字符串分配也少得多。
private static bool IsValidGtin(ReadOnlySpan<char> input, byte length)
{
if (input.Length != length)
{
return false;
}
if (!char.IsDigit(input[^1]))
{
return false;
}
var sum = 0d;
var multiplyByThree = true;
var inputWithoutCheckDigit = input[..^1];
for (var i = inputWithoutCheckDigit.Length - 1; i >= 0; i--)
{
var currentChar = inputWithoutCheckDigit[i];
if (!char.IsDigit(currentChar))
{
return false;
}
var value = char.GetNumericValue(currentChar);
if (multiplyByThree)
{
sum += value * 3;
}
else
{
sum += value;
}
multiplyByThree = !multiplyByThree;
}
var checkDigit = char.GetNumericValue(input[^1]);
return (sum + checkDigit) % 10 == 0;
}
如果需要,我here写了更多细节
答案 12 :(得分:0)
我编写了以下Python代码来快速,简洁地验证UPC代码:
def upc_validate(upc):
# check if upc is exactly 12 digits
upc = str(upc)
if len(upc) != 12 or len(list(filter(lambda x: 48 <= ord(x) <= 57, upc))) != 12:
return False
# validate CRC / check digit (sum of digits is a product of 10 after multiplying each odd digit by CRC)
digits = list(map(int, upc))
crc = digits[-1]
total = sum([digit if i & 1 else digit * crc for i, digit in enumerate(digits)])
return total % 10 == 0
答案 13 :(得分:0)
基于卢西亚诺的答案。
我删除了Linq依赖项,因为我在Java中也需要它。删除了填充到14位的填充,以便用于计算较长的ITF条形码的校验位。
长度不均的代码由(i + code.Length % 2)
处理,该31313
模式为长度不均的代码13131
。它避免了创建对象的过程,并且(在我的PC上)需要134毫秒来计算所有EAN-8代码的校验位。
我知道问题是关于一个IsValidEan()
方法的,但是如果您有一个包含方法的库,您可能仍然需要这个方法。 IsValidEan()
应该在进行长度和其他检查后调用此方法以进行校验数字验证。
/// <summary>
/// Calculate check digit for UPC-A, EAN-13, ITF-14 (or any ITF)
/// </summary>
/// <param name="code">This should include the check digit (append a fake check digit if needed)</param>
/// <returns></returns>
public static char CalculateCheckDigit(string code)
{
// Don't include check digit in the sum (< code.Length - 1)
int sum = 0;
for (int i = 0; i < code.Length - 1; i++)
sum += (code[i] - '0') * (((i + code.Length % 2) % 2 == 0) ? 3 : 1);
return (char)((10 - (sum % 10)) % 10 + '0');
}
Java版本:
public static char CalculateCheckDigit(String code) {
int sum = 0;
for(int i = 0; i < code.length() - 1; i++)
sum += ((int)code.charAt(i) - (int)'0') * (((i + code.length() % 2) % 2 == 0) ? 3 : 1);
return (char)((10 - (sum % 10)) % 10 + (int)'0');
}
答案 14 :(得分:0)
def check_digit():
users_gtin=raw_input("enter first seven digits of gtin ")
gtin_seven_digits=unicode(users_gtin)
if len(gtin_seven_digits) == 7 and gtin_seven_digits.isnumeric():
ck = ((((int(gtin_seven_digits[0])) + (int(gtin_seven_digits[2])) + (int(gtin_seven_digits[4])) + (int(gtin_seven_digits[6])))*3) + ((int(gtin_seven_digits[1])) + (int(gtin_seven_digits[3])) + (int(gtin_seven_digits[5])))) %10
final_ck = 10-ck
if final_ck == 10:
final_ck=0
print "Is your check digit",final_ck,"?"
else:
print "Is your check digit",final_ck,"?"
else:
print "please try typing an seven digit number"
check_digit()
choice=raw_input("enter (a) to restart or press anything other than the letter a to end this program <<<< ").upper()
if choice == "A":
check_digit()
check_digit()
答案 15 :(得分:-2)
在Clipper / Harbour中用于EAN8,EAN12,EAN13,EAN14
function DigitEan(cCodigo)
local cCode := AllTrim(cCodigo)
local nLen := Len(cCode)
local cc := 0
local i := 0
for i:=1 to nLen-1
cc+=(asc(substr(cCode,nLen-i,1))-48)*iif(i%2==0,1,3)
next
return ( (10-(cc%10))%10 )
答案 16 :(得分:-3)
private void button1_Click(object sender, EventArgs e)
{
string code = textBox1.Text;
string sBarcode = string.Empty;
sBarcode = IsValidGtin(code);
lblBarCode.Text = sBarcode;
}
public static string IsValidGtin(string code)
{
//if (code != (new Regex("[^0-9]")).Replace(code, ""))
//{
// // is not numeric
// return false;
//}
// pad with zeros to lengthen to 14 digits
switch (code.Length)
{
case 2:
code = code + "000000000";
break;
case 3:
code = code + "00000000";
break;
case 4:
code = code + "0000000";
break;
case 5:
code = code + "000000";
break;
case 6:
code = code + "00000";
break;
case 7:
code = code + "0000";
break;
case 8:
code = code + "000";
break;
case 9:
code = code + "00";
break;
case 10:
code = code + "0";
break;
case 11:
break;
case 12:
code = code.Substring(0, 11);
break;
//default:
// wrong number of digits
// return false;
}
// calculate check digit
int[] a = new int[12];
a[0] = int.Parse(code[0].ToString()) * 3;
a[1] = int.Parse(code[1].ToString());
a[2] = int.Parse(code[2].ToString()) * 3;
a[3] = int.Parse(code[3].ToString());
a[4] = int.Parse(code[4].ToString()) * 3;
a[5] = int.Parse(code[5].ToString());
a[6] = int.Parse(code[6].ToString()) * 3;
a[7] = int.Parse(code[7].ToString());
a[8] = int.Parse(code[8].ToString()) * 3;
a[9] = int.Parse(code[9].ToString());
a[10] = int.Parse(code[10].ToString()) * 3;
//a[11] = int.Parse(code[11].ToString());
//a[12] = int.Parse(code[12].ToString()) * 3;
int sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10];
string check = Convert.ToString((10 - (sum % 10)));
// evaluate check digit
// int last = int.Parse(code[13].ToString());
// return check == last;
code = code + check;
return code;
}