对于奇数和偶数长度的数字,如何最好地确定最右边数字左边的数字?

How best to determine the digit to the left of the rigthmost number for numbers with odd and even length?

我正在编写代码来检查一定数量的信用卡号输入是否有效。我写了:

function validCreditCard(value) {
    // accept only digits, dashes or spaces
    if (value.trim().length <= 1) return 'Value entered must be greater than 1';
    if (/[^0-9\s]+/.test(value)) return false;

    // Remove all white spaces
    value = value.replace(/\D/g, '');

    for (var i = 0; i < value.length; i++) {
    // code goes here
    // Loop through the string from the rightmost moving left and double the value of every second digit.
}

我一直在思考如何从最右边向左移动遍历字符串并将每个第二个数字的值加倍,因为字符串的长度可以偶数或奇数。例如,对于长度为 16(偶数)的输入,左边的第一个数字将是第 15 个位置(索引 14),对于奇数长度的输入(如 11),左边的第一个数字将是第 10 个位置(索引 9)。我编写的程序不适用于这两种情况,现在我想编写一个程序来同时满足这两种情况。如果不创建两个单独的检查来查看输入的长度是奇数还是偶数,我怎样才能最好地实现这一点?

P.S:一些在线实现也不适用于这两种情况。

Loop through the string from the rightmost moving left and double the value of every second digit

您可以使用 .reverse().map() 和余数运算符 %

let arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

var res = [...arr].reverse().map((a, i) => i % 2 ? a * 2 : a).reverse();

console.log(res);

要知道哪些是 "every second digit from the right",您实际上并不需要从头到尾迭代。也可以从左到右进行。要知道一个数字是否是这样的 "second" 数字,请将其 odd/even 奇偶校验与输入长度的奇偶校验进行比较。

像这样:

var parity = value.length % 2;
for (var i = 0; i < value.length; i++) {
    if (i % 2 === parity) {
        // "Special" treatment comes here
    } else {
        // "Normal" treatment comes here
    }
}

但如果输入的长度为奇数,您也可以在输入前加上一个零,使其长度为偶数:

if (value.length % 2) value = '0' + value;
for (var i = 0; i < value.length; i++) {
    if (i % 2 === 0) {
        // "Special" treatment comes here
    } else {
        // "Normal" treatment comes here
    }
}

您正在实施的称为 Luhn algorithm。所以使用长度的奇偶校验,它可能看起来像这样:

function validCreditCard(value) {
    // Accept only digits, dashes or spaces
    if (/[^0-9\s-]+/.test(value)) return false;
    // Get the digits only
    value = value.replace(/\D/g, "");
    // Need at least one digit
    if (!value.length) return false;
    var parity = value.length % 2;
    var sum = 0;
    for (var i = 0; i < value.length; i++) {
        sum += i % 2 === parity
            ? (value[i]*2) % 10 + (value[i] > '4') // Double, and add one if double > 9
            : +value[i]; // Normal case
    }
    return sum%10 === 0;
}

console.log(validCreditCard("4024007112651582"));

解释:

在循环中,我用 conditional ternary operator 替换了 if...else... 构造 - ... ? ... : ... - 这在两种情况下都需要分配一个值时很实用一个变量(在我们的例子中为 sum)。

对于 "normal" 个数字,sum 必须随着数字的值 (+value[i]) 增加。加一元运算符会将字符转换为其数值——因此 +'1' 变为 1.

对于 "special" 位,sum 必须增加该位值的两倍 (value[i]*2)。请注意,由于乘法,这里从字符串到整数的转换是自动发生的。

然后我们需要处理这个double值由两个数字组成的情况。例如:8*2 = 16。在这种情况下,结果数字不应该是 6,而是 7。因此我们添加 (value[i] > '4')。那确实是布尔表达式(falsetrue):当 double 有两个数字时它是真的。通过添加布尔值,它分别被强制为 0 或 1——这正是我们需要的。