Skip to content

Instantly share code, notes, and snippets.

@slyvain
Last active October 26, 2018 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slyvain/33f40ee7114bdbfd31865f35e4fa7364 to your computer and use it in GitHub Desktop.
Save slyvain/33f40ee7114bdbfd31865f35e4fa7364 to your computer and use it in GitHub Desktop.
/// <summary>
/// Generates an 8 digit Luhn identification (with checksum) wrapping the given internal ID.
/// </summary>
/// <param name="internalId">Internal ID</param>
/// <returns>Generated Luhn identification number</returns>
private long GenerateLuhnNumber(long internalId)
{
int baseLength = 8;
// generate a 8 digits sequence starting with the number of digits in the internalId
// and complete with the internalId with leading 0s
// eg. 30_000_845 => id is 845, and counts 3 digits
// or 75_000_109 => id is 5000109 and counts 7 digits
var sequence = new List<int>(baseLength);
sequence.Add(internalId.ToString().Length);
sequence.AddRange(internalId.ToString("d7").Select(x => Convert.ToInt32(x.ToString())));
// the last number is the check digit, use Luhn algorithm to calculate it:
// double every 2 numbers (starting from the rightmost), if result > 9, retract 9
// eg. 2*4 = 8 -> ok
// 2*8 = 16 -> not ok; 16-9 = 7 -> ok
bool alt = true;
int sumSequence = 0;
for (int i = sequence.Count - 1; i >= 0; i--)
{
var tmp = sequence[i];
if (alt)
{
tmp *= 2;
if (tmp > 9)
{
tmp -= 9;
}
}
sumSequence += tmp;
alt = !alt;
}
// now, calculate the checkdigit (multiply the sum by nine, and get the unit value)
// and add it at the end of the sequence
sequence.Add(sumSequence * 9 % 10);
return Convert.ToInt64(String.Join("", sequence));
}
/// <summary>
/// Extracts the internal ID wrapped in a Luhn identification number if it is valid.
/// </summary>
/// <param name="input">Luhn identification number</param>
/// <returns>The internal ID or NULL by default</returns>
private long? VerifyLuhnNumber(string input)
{
// keep only numeric characters
input = new string(input.Where(c => char.IsDigit(c)).ToArray());
// extract the digits
int[] sequence = input.Select(x => Convert.ToInt32(x.ToString())).ToArray();
// calculate the checksum starting from the 2nd rightmost characters (rightmost being the checkdigit)
int checkSum = 0;
bool alt = true;
for (int i = sequence.Length - 2; i >= 0; i--)
{
var tmp = sequence[i];
if (alt)
{
tmp *= 2;
if (tmp > 9)
{
tmp -= 9;
}
}
checkSum += tmp;
alt = !alt;
}
// add the check digit
checkSum += sequence.Last();
if (checkSum % 10 == 0)
{
// valid, extract the internal Id
int idLength = sequence[0];
var tmpIdStr = String.Join("", sequence.Skip(sequence.Count() - 1 - idLength).Take(idLength));
if (tmpIdStr.Any())
{
long tmpValidLong;
if (long.TryParse(tmpIdStr, out tmpValidLong))
{
return tmpValidLong;
}
}
}
// return NULL by default
return null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment