编写 Luhn 算法

Programming a Luhn Algorithm

我有一个 luhn 算法,我正在尝试按照维基百科上的算法步骤进行操作,并且它适用于他们提供的示例。我认为这是正确的。但它不适用于我的任何个人卡。也没有我在寻找解决方案时发现的任何测试值。

我已经看到使用 lamba 和内联 linq 的其他解决方案。但我不想复制和粘贴任何东西。我宁愿真正理解我在编码什么。

49927398716      pass
49927398717      fail
1234567812345678 fail 
1234567812345670 pass (mine fails this one)

我的代码如下。

    private bool CalculateLuhnAlgorithm()
    {
        string newListOfNumbers = this._number; //this._number is a string
        int sumOfAllValues = 0;
        if (_cardType != CardType.Unavailable)
        {
            //odd numbers minus the check Digit. 
            for (int i = this._number.Length - 2; i > 0; i -= 2)
            {
                int number = (int)char.GetNumericValue(this._number[i]) * 2;
                if (number >= 10)
                {
                    string concatinatedNumber = number.ToString();
                    int firstNumber = (int)char.GetNumericValue(concatinatedNumber[0]);
                    int secondNumber = (int)char.GetNumericValue(concatinatedNumber[1]);
                    number = firstNumber + secondNumber;
                }
                newListOfNumbers = newListOfNumbers.Remove(i, 1);
                newListOfNumbers = newListOfNumbers.Insert(i, number.ToString());
            }

            // add up the complete total
            foreach (char c in newListOfNumbers)
            {
                sumOfAllValues += (int)char.GetNumericValue(c);
            }

        }

        // get the luhn validity
        return (sumOfAllValues %10) == 0;
    }

问题是您的 for 循环在 i > 0 期间继续。这意味着您永远不会将第一个数字加倍。它应该在 i >= 0.

期间继续

下面是一些其他的建议。

当您将 number 加倍并且大于 10 时,您可以这样做

if(number > 10)
    number = (number % 10) + 1;

这是有效的,因为最高的单个数字值 (9) 加倍是 (18)。所以第一个数字总是 1,你可以 mod 数字乘以 10 得到第二个数字。

您应该添加一个检查以确保该字符串具有偶数位数,并且可能具体的下限和上限取决于您使用的帐号是什么。

与其创建第二个包含 "odd" 数字加倍的字符串,不如在遍历数字时跟踪总和,如下所示。

private bool CalculateLuhnAlgorithm()
{
    if(this.number.Length % 2 != 0)
        return false; // Or maybe throw an exception?
    if (_cardType != CardType.Unavailable)
    {
        int sumOfAllValues = 0;
        //odd numbers minus the check Digit. 
        for (int i = 0; i < this._number.Length; i++)
        {
            if(i%2 != 0) // because i is 0 based instead of 1 based.
                sumOfAllValues += (int)char.GetNumericValue(this._number[i])
            else
            {
                int number = (int)char.GetNumericValue(this._number[i]) * 2;
                if (number >= 10)
                {
                    number = (number % 10) + 1;
                }
                sumOfAllValues += number;
            }
        }

        // get the luhn validity
        return (sumOfAllValues %10) == 0;
    }
    else
    {
         // Not completely sure what this should do, 
         // but in your code it just results in true.
         return true;
    }
}

最后,您可能希望将 char.GetNumericValue 替换为 int.TryParse,以便验证包含非数字值的字符串。 char.GetNumericValue returns -1 对于非数字值。

int digit = 0;
if(!int.TryParse(this._number.SubString(i, 1), out digit)
{
    return false;  // Or throw an exception.
}