如何在 JavaScript 中验证 EAN / GTIN 条形码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13605340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to validate a EAN / GTIN barcode in JavaScript
提问by dom
How can I check if a string is a valid EAN / GTIN barcode in JavaScript?
如何在 JavaScript 中检查字符串是否是有效的 EAN / GTIN 条形码?
I need checks for EAN8, EAN12, EAN13, EAN14, EAN18 and also GTIN12, GTIN13, GTIN14.
我需要检查 EAN8、EAN12、EAN13、EAN14、EAN18 以及 GTIN12、GTIN13、GTIN14。
回答by dom
EDITI also created a npm module, which can be found on github.
编辑我还创建了一个 npm 模块,可以在github上找到。
I created a small library, which supports EAN8, EAN12, EAN13, EAN14, EAN18, GTIN12, GTIN13 and GTIN14.
我创建了一个小库,支持 EAN8、EAN12、EAN13、EAN14、EAN18、GTIN12、GTIN13 和 GTIN14。
It works inside node.js and all modern browsers.
它适用于 node.js 和所有现代浏览器。
barcoder.js:
条码器.js:
/*!
* Barcoder
* Copyright (c) 2013 mifitto GmbH <[email protected]>
* MIT Licensed
*/
(function() {
'use strict';
/**
* Library version.
*/
var version = '1.1.0';
/**
* Supported formats
*/
var minValidLength = 6;
var maxValidLength = 18;
var usualValidChars = /^\d+$/;
var formats = {
'ean8' : { validChars : /^\d+$/, validLength : 8 },
'ean12' : { validChars : /^\d+$/, validLength : 12 },
'ean13' : { validChars : /^\d+$/, validLength : 13 },
'ean14' : { validChars : /^\d+$/, validLength : 14 },
'ean18' : { validChars : /^\d+$/, validLength : 18 },
'gtin12' : { validChars : /^\d+$/, validLength : 12 },
'gtin13' : { validChars : /^\d+$/, validLength : 13 },
'gtin14' : { validChars : /^\d+$/, validLength : 14 }
};
/**
* Validates the checksum (Modulo 10)
* GTIN implementation factor 3
*
* @param {String} value The barcode to validate
* @return {Boolean}
* @api private
*/
var validateGtin = function( value ) {
var barcode = value.substring( 0, value.length - 1 );
var checksum = parseInt( value.substring( value.length - 1 ), 10 );
var calcSum = 0;
var calcChecksum = 0;
barcode.split('').map(function( number, index ) {
number = parseInt( number, 10 );
if ( value.length % 2 === 0 ) {
index += 1;
}
if ( index % 2 === 0 ) {
calcSum += number;
}
else {
calcSum += number * 3;
}
});
calcSum %= 10;
calcChecksum = (calcSum === 0) ? 0 : (10 - calcSum);
if ( calcChecksum !== checksum ) {
return false;
}
return true;
};
/**
* Barcoder class
*
* @param {string} format See formats
* @param {Object} options Valid option `enableZeroPadding`, defaults to `true`
* @api public
*/
var Barcoder = function ( format, options ) {
if ( format && !formats[format] ) throw new Error( '"format" invalid' );
this.format = (format) ? formats[format] : 'autoSelect';
this.options = (options) ? options : { enableZeroPadding : true };
if ( !this.options.enableZeroPadding ) {
this.options.enableZeroPadding = true;
}
};
/**
* Validates a barcode
*
* @param {string} barcode EAN/GTIN barcode
* @return {Boolean}
* @api public
*/
Barcoder.prototype.validate = function( barcode ) {
var self = this;
if ( self.format === 'autoSelect' ) {
if ( barcode.length < minValidLength || barcode.length > maxValidLength ) {
return false;
}
var isValidGtin = validateGtin( barcode );
var paddedBarcode = barcode;
var successfullyPadded = false;
if ( !isValidGtin ) {
var possiblyMissingZeros = maxValidLength - barcode.length;
while( possiblyMissingZeros-- ) {
paddedBarcode = '0' + paddedBarcode;
if ( validateGtin( paddedBarcode ) ) {
isValidGtin = true;
successfullyPadded = true;
break;
}
}
}
return {
possibleType: (barcode.length > 8) ? 'GTIN' + barcode.length : 'EAN8 / padded GTIN',
isValid: isValidGtin
};
}
var validChars = self.format.validChars;
var validLength = self.format.validLength;
var enableZeroPadding = self.options.enableZeroPadding;
if ( validChars.exec( barcode ) === null ) {
return false;
}
if ( enableZeroPadding && barcode.length < validLength ) {
var missingZeros = validLength - barcode.length;
while( missingZeros-- ) {
barcode = '0' + barcode;
}
}
else if ( !enableZeroPadding && barcode.length != validLength ) {
return false;
}
else if ( barcode.length > validLength ) {
return false;
}
return validateGtin( barcode );
};
/**
* Export
*/
if ( 'undefined' !== typeof module && module.exports ) {
module.exports = Barcoder;
exports.version = version;
}
if ( 'undefined' === typeof ender ) {
this['Barcoder'] = Barcoder;
}
if ( 'function' === typeof define && define.amd ) {
define('Barcoder', [], function () {
return Barcoder;
});
}
}).call( this );
Installation:
安装:
$ npm install barcoder
Usage:
用法:
var Barcoder = require('barcoder');
var ean1 = '0016T20054453';
var ean2 = '9330071314999';
var validator = new Barcoder('ean13');
console.log( '%s ean1 is valid: %s', ean1, validator.validate( ean1 ) );
console.log( '%s ean2 is valid: %s', ean1, validator.validate( ean2 ) );
// or /w automatic type selection
validator = new Barcoder();
var validation1 = validator.validate( ean1 );
var validation2 = validator.validate( ean2 );
console.log( '%s is valid: %s and has guessed type: %s', ean1, validation1.isValid, validation1.possibleType );
console.log( '%s is valid: %s and has guessed type: %s', ean2, validation2.isValid, validation2.possibleType );
回答by Lennart Rolland
I am not sure why, but @doms solution did not work correctly for me. Also I would like to both calculatenew codes as well as verifyold ones. I ended up with this, that I have verified to be working in my browsers atleast:
我不知道为什么,但@doms 解决方案对我不起作用。此外,我想既计算新代码又验证旧代码。我最终得到了这个,我已经验证至少可以在我的浏览器中工作:
function eanCheckDigit(s){
var result = 0;
for (let counter = s.length-1; counter >=0; counter--){
result = result + parseInt(s.charAt(counter)) * (1+(2*(counter % 2)));
}
return (10 - (result % 10)) % 10;
}
2020 Update -Had to add let
in front of counter otherwise it was saying counter was not defined.
2020 年更新 -必须let
在计数器前添加,否则会显示未定义计数器。
2020 2nd Update -After lots of fighting with this, I realized this formula only works for UPC's passed in that are 10(or even digits in length). If you pass one in that is 11 digits, this doesn't work. So I've modified it to work with any length UPC. Let me know if this can be written cleaner.
2020 年第 2 次更新 -经过多次与此斗争后,我意识到此公式仅适用于传入的 10(甚至是数字长度)的 UPC。如果你传递一个 11 位数字,这不起作用。所以我修改了它以使用任何长度的 UPC。让我知道这是否可以写得更干净。
function eanCheckDigit(s){
let result = 0;
let i = 1;
for (let counter = s.length-1; counter >=0; counter--){
result = result + parseInt(s.charAt(counter)) * (1+(2*(i % 2)));
i++;
}
return (10 - (result % 10)) % 10;
}
回答by Kjeld
Here is a short version that can check if the EAN13 check digit is valid:
这是一个简短的版本,可以检查 EAN13 校验位是否有效:
var checkSum = ean.split('').reduce(function(p,v,i) {
return i % 2 == 0 ? p + 1 * v : p + 3 * v;
}, 0);
if (checkSum % 10 != 0) {
alert('error');
}
回答by Rin and Len
Here is my solution, checking for different length barcodes using the specification to calculate the check digit at the end (see note):
这是我的解决方案,使用规范检查不同长度的条形码以计算末尾的校验位(见注释):
// ean/gtin validation for 8, 12, 13 & 14 digit barcodes
function codeOnBlur(barcode) {
var barcodeLengthArr = [8, 12, 13, 14];
var allowedChars = new RegExp(/\d{8,14}/); // >7 & <15
// put numbers in array and convert to type Int.
var barcodeArray = barcode.split('');
for( var i = 0; i < barcodeArray.length; i++) {
barcodeArray[i] = parseInt(barcodeArray[i], 10);
}
// get the last digit for checking later
var checkDigit = barcodeArray.slice(-1)[0];
// we'll need a to compare it to this:
var remainder = 0;
// check if input (barcode) is in the array and check against the regex.
if (($.inArray(barcode.length, barcodeLengthArr) > -1) && (allowedChars.test(barcode))) {
console.log("barcodeArray ", barcodeArray, " :: checkDigit ", checkDigit);
// Pop the last item from the barcode array, test if the length is
// odd or even (see note on calculating the check digit) and
// multiply each item in array based in position:
var total = 0;
barcodeArray.pop();
// odd length after pop
if (barcodeArray.length % 2 === 1) {
for (var i = barcodeArray.length - 1; i >= 0; i--) {
barcodeArray[i] = i % 2 === 0 ? barcodeArray[i] * 3 : barcodeArray[i] * 1;
total += barcodeArray[i];
}
// even length after pop
} else if (barcodeArray.length % 2 === 0) {
for (var i = barcodeArray.length - 1; i >= 0; i--) {
barcodeArray[i] = i % 2 === 0 ? barcodeArray[i] * 1 : barcodeArray[i] * 3;
total += barcodeArray[i];
}
} else {
// validation passed = false
}
// calculate the remainder of totalrounded up to nearest multiple of 10:
remainder = (Math.ceil((total + 1) / 10) * 10) - total;
console.log("loop total = ", total, ", remainder: ", remainder);
if ( remainder === checkDigit ) {
//validation passed = true;
return;
} else {
//validation passed = false;
}
} else {
//validation Passed = false;
}
}
I'm certain this code can be tidied up some :)
我确信这段代码可以整理一些:)
Manually checking the "integrity bit" or check digit:
手动检查“完整性位”或校验位:
barcode: 13: 4 0 1 1 2 0 0 2 9 6 9 0 8
8: 5 0 8 1 8 9 0 7
multiplier: 3 1 3 1 3 1 3 1 3 1 3 1 check digit
To take the 8 digit code working backwards:
将 8 位代码逆向工作:
0*1 + 9*3 + 8*1 + 1*3 + 8*1 + 0*3 + 5*1 = 73
Difference from 73 to 80 is 7 (the specification will have you round up to
the nearest power of 10).
7 is both the check digit and the remainder of 80-73.
7 既是校验位又是 80-73 的余数。
回答by ElectroBit
I'm sorry if this code is a little too long, but this is what I have for verifying an EAN13 barcode:
如果此代码有点太长,我很抱歉,但这是我用于验证 EAN13 条形码的内容:
function isBarcode(barcode) {
if (typeof barcode === 'number') {
throw 'RuntimeError: Barcode MUST NOT be in number format'
} else if (barcode.length!==12) {
throw 'RuntimeError: String length is not 12'
};
var _= barcode.toString().split("")
var _1 = 0
var _2 = 0
var __
for ($=0;$<=10;++$) {
_1+=+_[$]
};for ($=10;$>=0;$-=2) {
_2+=+_[$]
};_2*=2
var _3 = _1+_2
__=+_3.toString().substring(1,2)
if (__>9) {
__=+_3.toString().substring(1,2)
} else if (__===0) {
__=10
};
__=10-__
if (__===+_[11]) {
return true
}
return false
};