-
-
Save taurit/b9316e0a0efb719fbc43d6487e660e72 to your computer and use it in GitHub Desktop.
Italian Fiscal Code validation in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Validate Italian Fiscal Code (https://en.wikipedia.org/wiki/Italian_fiscal_code_card) | |
/// </summary> | |
/// <param name="fiscalCode">code to be checked</param> | |
/// <returns><c>true</c> if checksum is valid, <c>false</c> otherwise</returns> | |
/// <remarks> | |
/// Based on: https://gist.github.com/supix/97dfe1e2c4b804bd3721faf4bec1c573 | |
/// </remarks> | |
public static bool IsFiscalCodeValid(string fiscalCode) | |
{ | |
if (fiscalCode == null) return false; | |
const string regex = | |
@"^(?:[B-DF-HJ-NP-TV-Z](?:[AEIOU]{2}|[AEIOU]X)|[AEIOU]{2}X|[B-DF-HJ-NP-TV-Z]{2}[A-Z]){2}[\dLMNP-V]{2}(?:[A-EHLMPR-T](?:[04LQ][1-9MNP-V]|[1256LMRS][\dLMNP-V])|[DHPS][37PT][0L]|[ACELMRT][37PT][01LM])(?:[A-MZ][1-9MNP-V][\dLMNP-V]{2}|[A-M][0L](?:[\dLMNP-V][1-9MNP-V]|[1-9MNP-V][0L]))[A-Z]$"; | |
if (!Regex.IsMatch(fiscalCode, regex)) return false; | |
#region static maps | |
var oddMap = new Dictionary<char, int> | |
{ | |
{ '0', 1 }, | |
{ '1', 0 }, | |
{ '2', 5 }, | |
{ '3', 7 }, | |
{ '4', 9 }, | |
{ '5', 13 }, | |
{ '6', 15 }, | |
{ '7', 17 }, | |
{ '8', 19 }, | |
{ '9', 21 }, | |
{ 'A', 1 }, | |
{ 'B', 0 }, | |
{ 'C', 5 }, | |
{ 'D', 7 }, | |
{ 'E', 9 }, | |
{ 'F', 13 }, | |
{ 'G', 15 }, | |
{ 'H', 17 }, | |
{ 'I', 19 }, | |
{ 'J', 21 }, | |
{ 'K', 2 }, | |
{ 'L', 4 }, | |
{ 'M', 18 }, | |
{ 'N', 20 }, | |
{ 'O', 11 }, | |
{ 'P', 3 }, | |
{ 'Q', 6 }, | |
{ 'R', 8 }, | |
{ 'S', 12 }, | |
{ 'T', 14 }, | |
{ 'U', 16 }, | |
{ 'V', 10 }, | |
{ 'W', 22 }, | |
{ 'X', 25 }, | |
{ 'Y', 24 }, | |
{ 'Z', 23 } | |
}; | |
var evenMap = new Dictionary<char, int> | |
{ | |
{ '0', 0 }, | |
{ '1', 1 }, | |
{ '2', 2 }, | |
{ '3', 3 }, | |
{ '4', 4 }, | |
{ '5', 5 }, | |
{ '6', 6 }, | |
{ '7', 7 }, | |
{ '8', 8 }, | |
{ '9', 9 }, | |
{ 'A', 0 }, | |
{ 'B', 1 }, | |
{ 'C', 2 }, | |
{ 'D', 3 }, | |
{ 'E', 4 }, | |
{ 'F', 5 }, | |
{ 'G', 6 }, | |
{ 'H', 7 }, | |
{ 'I', 8 }, | |
{ 'J', 9 }, | |
{ 'K', 10 }, | |
{ 'L', 11 }, | |
{ 'M', 12 }, | |
{ 'N', 13 }, | |
{ 'O', 14 }, | |
{ 'P', 15 }, | |
{ 'Q', 16 }, | |
{ 'R', 17 }, | |
{ 'S', 18 }, | |
{ 'T', 19 }, | |
{ 'U', 20 }, | |
{ 'V', 21 }, | |
{ 'W', 22 }, | |
{ 'X', 23 }, | |
{ 'Y', 24 }, | |
{ 'Z', 25 } | |
}; | |
#endregion static maps | |
var total = 0; | |
for (var i = 0; i < 15; i += 2) total += oddMap[fiscalCode[i]]; | |
for (var i = 1; i < 15; i += 2) total += evenMap[fiscalCode[i]]; | |
return fiscalCode[15] == (char)('A' + total % 26); | |
} | |
/* Xunit tests for validator */ | |
[Fact] | |
public void WhenCodeContainsInvalidControlCharacter_ReturnsFalse() | |
{ | |
// example of valid code from https://en.wikipedia.org/wiki/Italian_fiscal_code_card | |
var code = "MRTMTT25D09F205X"; // last "X" is invalid, control character should be "Z" | |
// Act | |
var valid = ItalianFiscalCodeValidator.IsFiscalCodeValid(code); | |
// Assert | |
Assert.Equal(false, valid); | |
} | |
[Fact] | |
public void WhenCodeIsTooShort_ReturnsFalse() | |
{ | |
// code should contain 15 characters | |
var code0 = ""; | |
var code1 = "M"; | |
var code2 = "MR"; | |
var code14 = "MRTMTT25D09F205"; // last "X" is invalid, control character should be "Z" | |
// Act | |
var valid0 = ItalianFiscalCodeValidator.IsFiscalCodeValid(code0); | |
var valid1 = ItalianFiscalCodeValidator.IsFiscalCodeValid(code1); | |
var valid2 = ItalianFiscalCodeValidator.IsFiscalCodeValid(code2); | |
var valid14 = ItalianFiscalCodeValidator.IsFiscalCodeValid(code14); | |
// Assert | |
Assert.Equal(false, valid0); | |
Assert.Equal(false, valid1); | |
Assert.Equal(false, valid2); | |
Assert.Equal(false, valid14); | |
} | |
[Fact] | |
public void WhenNullCodeIsPassed_ReturnsFalse() | |
{ | |
// Act | |
var valid = ItalianFiscalCodeValidator.IsFiscalCodeValid(null); | |
// Assert | |
Assert.Equal(false, valid); | |
} | |
[Fact] | |
public void WhenValidCodeIsGiven_ForForeignCitizen_ReturnsTrue() | |
{ | |
// example of valid code from https://en.wikipedia.org/wiki/Italian_fiscal_code_card | |
var code = "MLLSNT82P65Z404U"; | |
// Act | |
var valid = ItalianFiscalCodeValidator.IsFiscalCodeValid(code); | |
// Assert | |
Assert.Equal(true, valid); | |
} | |
[Fact] | |
public void WhenValidCodeIsGiven_ReturnsTrue() | |
{ | |
// example of valid code from https://en.wikipedia.org/wiki/Italian_fiscal_code_card | |
var code = "MRTMTT25D09F205Z"; | |
// Act | |
var valid = ItalianFiscalCodeValidator.IsFiscalCodeValid(code); | |
// Assert | |
Assert.Equal(true, valid); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment