Implementation of Luhn algorithm

2019-03-18 20:57发布

I am trying to implement simple validation of credit card numbers. I read about the Luhn algorithm on Wikipedia:

  1. Counting from the check digit, which is the rightmost, and moving left, double the value of every second digit.
  2. Sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5) together with the undoubled digits from the original number.
  3. If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.

On Wikipedia, the description of the Luhn algorithm is very easily understood. However, I have also seen other implementations of the Luhn algorithm on Rosetta Code and elsewhere.

Those implementations work very well, but I am confused about why they can use an array to do the work. The array they use seems to have no relation with Luhn algorithm, and I can't see how they achieve the steps described on Wikipedia.

Why are they using arrays? What is the significance of them, and how are they used to implement the algorithm as described by Wikipedia?

12条回答
女痞
2楼-- · 2019-03-18 21:42
const LuhnCheckCard = (number) => {
  if (/[^0-9-\s]+/.test(number) || number.length === 0)
    return false;

  return ((number.split("").map(Number).reduce((prev, digit, i) => {
    (!(( i & 1 ) ^ number.length)) && (digit *= 2);    
    (digit > 9) && (digit -= 9);    
    return prev + digit;
  }, 0) % 10) === 0);
}

console.log(LuhnCheckCard("4532015112830366")); // true
console.log(LuhnCheckCard("gdsgdsgdsg")); // false
查看更多
兄弟一词,经得起流年.
3楼-- · 2019-03-18 21:47

A very fast and elegant implementation of the Luhn algorithm following:

const isLuhnValid = function luhn(array) {
      return function (number) {
        let len = number ? number.length : 0,
          bit = 1,
          sum = 0;

        while (len--) {
          sum += !(bit ^= 1) ? parseInt(number[len], 10) : array[number[len]];
        }

        return sum % 10 === 0 && sum > 0;
      };
    }([0, 2, 4, 6, 8, 1, 3, 5, 7, 9]);

console.log(isLuhnValid("4112344112344113".split(""))); // true
console.log(isLuhnValid("4112344112344114".split(""))); // false

On my dedicated git repository you can grab it and retrieve more info (like benchmarks link and full unit tests for ~50 browsers and some node.js versions).

Or you can simply install it via bower or npm. It works both on browsers and/or node.

bower install luhn-alg
npm install luhn-alg
查看更多
相关推荐>>
4楼-- · 2019-03-18 21:47
function luhnCheck(value) {
  return 0 === (value.replace(/\D/g, '').split('').reverse().map(function(d, i) {
    return +['0123456789','0246813579'][i % 2][+d];
  }).reduce(function(p, n) {
    return p + n;
  }) % 10);
}
查看更多
放我归山
5楼-- · 2019-03-18 21:48

Code is the following:

var LuhnCheck = (function()
{
    var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
    return function(str)
    {
        var counter = 0;
        var incNum;
        var odd = false;
        var temp = String(str).replace(/[^\d]/g, "");
        if ( temp.length == 0)
            return false;
        for (var i = temp.length-1; i >= 0; --i)
        {
            incNum = parseInt(temp.charAt(i), 10);
            counter += (odd = !odd)? incNum : luhnArr[incNum];
        }
        return (counter%10 == 0);
    }
})();

The variable counter is the sum of all the digit in odd positions, plus the double of the digits in even positions, when the double exceeds 10 we add the two numbers that make it (ex: 6 * 2 -> 12 -> 1 + 2 = 3)

The Array you are asking about is the result of all the possible doubles

var luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];

  • 0 * 2 = 0 --> 0
  • 1 * 2 = 2 --> 2
  • 2 * 2 = 4 --> 4
  • 3 * 2 = 6 --> 6
  • 4 * 2 = 8 --> 8
  • 5 * 2 = 10 --> 1+0 --> 1
  • 6 * 2 = 12 --> 1+2 --> 3
  • 7 * 2 = 14 --> 1+4 --> 5
  • 8 * 2 = 16 --> 1+6 --> 7
  • 9 * 2 = 18 --> 1+8 --> 9

So for example

luhnArr[3] --> 6 (6 is in 3rd position of the array, and also 3 * 2 = 6)
luhnArr[7] --> 5 (5 is in 7th position of the array, and also 7 * 2 = 14 -> 5 )
查看更多
三岁会撩人
6楼-- · 2019-03-18 21:49

Another alternative:

function luhn(digits) {
    return /^\d+$/.test(digits) && !(digits.split("").reverse().map(function(checkDigit, i) { 
        checkDigit = parseInt(checkDigit, 10);
        return i % 2 == 0
            ? checkDigit
            : (checkDigit *= 2) > 9 ? checkDigit - 9 : checkDigit;
    }).reduce(function(previousValue, currentValue) {
        return previousValue + currentValue;
    }) % 10);
}
查看更多
Deceive 欺骗
7楼-- · 2019-03-18 21:52

Unfortunately none of the codes above worked for me. But I found on GitHub a working solution

// takes the form field value and returns true on valid number
function valid_credit_card(value) {
// accept only digits, dashes or spaces
    if (/[^0-9-\s]+/.test(value)) return false;

// The Luhn Algorithm. It's so pretty.
    var nCheck = 0, nDigit = 0, bEven = false;
    value = value.replace(/\D/g, "");

    for (var n = value.length - 1; n >= 0; n--) {
        var cDigit = value.charAt(n),
            nDigit = parseInt(cDigit, 10);

        if (bEven) {
            if ((nDigit *= 2) > 9) nDigit -= 9;
        }

        nCheck += nDigit;
        bEven = !bEven;
    }

    return (nCheck % 10) == 0;
}
查看更多
登录 后发表回答