这里提供一些扩展方法,用于计算Luhn校验位、验证带有校验位的数字以及给数字添加校验位。在.NET 4.5中进行了测试。
有针对字符串、整数、长整数和列表的扩展方法。
我从rosettacode.org获取了一些灵感。
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
public static class CheckDigitExtension
{
static readonly int[] Results = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 };
#region extension methods for IList<int>
public static int CheckDigit(this IList<int> digits)
{
var i = 0;
var lengthMod = digits.Count%2;
return (digits.Sum(d => i++ % 2 == lengthMod ? d : Results[d]) * 9) % 10;
}
public static IList<int> AppendCheckDigit(this IList<int> digits)
{
var result = digits;
result.Add(digits.CheckDigit());
return result;
}
public static bool HasValidCheckDigit(this IList<int> digits)
{
return digits.Last() == CheckDigit(digits.Take(digits.Count - 1).ToList());
}
#endregion extension methods for IList<int>
#region extension methods for strings
private static IList<int> ToDigitList(this string digits)
{
return digits.Select(d => d - 48).ToList();
}
public static string CheckDigit(this string digits)
{
return digits.ToDigitList().CheckDigit().ToString(CultureInfo.InvariantCulture);
}
public static string AppendCheckDigit(this string digits)
{
return digits + digits.CheckDigit();
}
public static bool HasValidCheckDigit(this string digits)
{
return digits.ToDigitList().HasValidCheckDigit();
}
#endregion extension methods for strings
#region extension methods for integers
private static IList<int> ToDigitList(this int digits)
{
return digits.ToString(CultureInfo.InvariantCulture).Select(d => d - 48).ToList();
}
public static int CheckDigit(this int digits)
{
return digits.ToDigitList().CheckDigit();
}
public static int AppendCheckDigit(this int digits)
{
return digits * 10 + digits.CheckDigit();
}
public static bool HasValidCheckDigit(this int digits)
{
return digits.ToDigitList().HasValidCheckDigit();
}
#endregion extension methods for integers
#region extension methods for int64s
private static IList<int> ToDigitList(this Int64 digits)
{
return digits.ToString(CultureInfo.InvariantCulture).Select(d => d - 48).ToList();
}
public static int CheckDigit(this Int64 digits)
{
return digits.ToDigitList().CheckDigit();
}
public static Int64 AppendCheckDigit(this Int64 digits)
{
return digits * 10 + digits.CheckDigit();
}
public static bool HasValidCheckDigit(this Int64 digits)
{
return digits.ToDigitList().HasValidCheckDigit();
}
#endregion extension methods for int64s
}
这里有一些XUnit测试用例,展示了扩展方法是如何工作的。
public class CheckDigitExtensionShould
{
[Fact]
public void ComputeCheckDigits()
{
Assert.Equal(0, (new List<int> { 0 }).CheckDigit());
Assert.Equal(8, (new List<int> { 1 }).CheckDigit());
Assert.Equal(6, (new List<int> { 2 }).CheckDigit());
Assert.Equal(0, (new List<int> { 3, 6, 1, 5, 5 }).CheckDigit());
Assert.Equal(0, 36155.CheckDigit());
Assert.Equal(8, (new List<int> { 3, 6, 1, 5, 6 }).CheckDigit());
Assert.Equal(8, 36156.CheckDigit());
Assert.Equal(6, 36157.CheckDigit());
Assert.Equal("6", "36157".CheckDigit());
Assert.Equal("3", "7992739871".CheckDigit());
}
[Fact]
public void ValidateCheckDigits()
{
Assert.True((new List<int> { 3, 6, 1, 5, 6, 8 }).HasValidCheckDigit());
Assert.True(361568.HasValidCheckDigit());
Assert.True("361568".HasValidCheckDigit());
Assert.True("79927398713".HasValidCheckDigit());
}
[Fact]
public void AppendCheckDigits()
{
Console.WriteLine("36156".CheckDigit());
Console.WriteLine("36156".AppendCheckDigit());
Assert.Equal("361568", "36156".AppendCheckDigit());
Assert.Equal("79927398713", "7992739871".AppendCheckDigit());
}
}
sum ≡ 0 mod 10
,它的运行结果不正确(检查总是失败)。 - Gebb