From f9cc8453f6aa6b7d28248ddb9390e175e09517c0 Mon Sep 17 00:00:00 2001 From: Augusto Destrero Date: Wed, 29 Jan 2014 12:41:11 +0100 Subject: [PATCH 1/2] * modified regexp to accept omocodie (http://it.wikipedia.org/wiki/Omocodia) * isvalid only if control character matches * compute birthday date also for omocodie * updated tests and removed a test on a bug that is now fixed --- codicefiscale.py | 26 +++++++++++++++++++------- tests.py | 22 ++++++++++++++-------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/codicefiscale.py b/codicefiscale.py index f5bc96e..cbc0614 100644 --- a/codicefiscale.py +++ b/codicefiscale.py @@ -23,8 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """ -__version__ = '0.8' -__author__ = "Emanuele Rocca" +__version__ = '0.9' +__author__ = "Emanuele Rocca, Augusto Destrero" import re # pylint: disable=W0402 @@ -36,7 +36,7 @@ MONTHSCODE = [ 'A', 'B', 'C', 'D', 'E', 'H', 'L', 'M', 'P', 'R', 'S', 'T' ] # pylint: disable=C0301 -PATTERN = "^[A-Z]{6}[0-9]{2}([A-E]|[HLMPRST])[0-9]{2}[A-Z][0-9]([A-Z]|[0-9])[0-9][A-Z]$" +_pattern = re.compile("^[A-Z]{6}[0-9LMNPQRSTUV]{2}[ABCDEHLMPRST]{1}[0-9LMNPQRSTUV]{2}[A-Z]{1}[0-9LMNPQRSTUV]{3}[A-Z]{1}$") def isvalid(code): """``isvalid(code) -> bool`` @@ -46,7 +46,14 @@ def isvalid(code): eg: isvalid('RCCMNL83S18D969H') -> True isvalid('RCCMNL83S18D969') -> False """ - return isinstance(code, basestring) and re.match(PATTERN, code) is not None + if not isinstance(code, basestring): + return False + if len(code) != 16: + return False + code = code.upper() + if _pattern.match(code) is None: + return False + return (control_code(code[0:15]) == code[15]) # Fiscal code calculation def __common_triplet(input_string, consonants, vowels): @@ -186,11 +193,16 @@ def get_birthday(code): """ assert isvalid(code) - day = int(code[9:11]) - day = day < 32 and day or day - 40 + day_year_charmap = {} + for idx, char in enumerate(string.digits): + day_year_charmap[char] = idx + for idx, char in enumerate('LMNPQRSTUV'): + day_year_charmap[char] = idx + day = day_year_charmap[code[9]] * 10 + day_year_charmap[code[10]] + day = day < 32 and day or day - 40 month = MONTHSCODE.index(code[8]) + 1 - year = int(code[6:8]) + year = day_year_charmap[code[6]] * 10 + day_year_charmap[code[7]] return "%02d-%02d-%02d" % (day, month, year) diff --git a/tests.py b/tests.py index 49da874..35994c7 100644 --- a/tests.py +++ b/tests.py @@ -20,9 +20,13 @@ def test_isvalid(self): 'RCCMNL83S18D969H', 'MRSMSR81D60Z611H', 'CNTCHR83T41D969D', - 'XXXXXX77A01Z2P6B', 'FOXDRA26C24H872Y', - 'MAILCU91A25F839D' ) + 'MAILCU91A25F839D', + 'RSSMRA45C12F205C', + 'RSSMRA45C12F20RX', + 'RSSMRA45C12F2L5N', + 'RSSMRA45C12F2LRI', + 'RSSMRAQRCMNFNLRG',) for cf in valid: self.assertTrue(isvalid(cf)) @@ -34,7 +38,12 @@ def test_get_birthday(self): 'MRSMSR81D60Z611H': '20-04-81', 'CNTCHR83T41D969D': '01-12-83', 'FOXDRA26C24H872Y': '24-03-26', - 'MAILCU91A25F839D': '25-01-91' + 'MAILCU91A25F839D': '25-01-91', + 'RSSMRA45C12F205C': '12-03-45', + 'RSSMRA45C12F20RX': '12-03-45', + 'RSSMRA45C12F2L5N': '12-03-45', + 'RSSMRA45C12F2LRI': '12-03-45', + 'RSSMRAQRCMNFNLRG': '12-03-45', } for cf, expected in inputs.items(): @@ -142,13 +151,10 @@ def test_01_locale_bug(self): actual = build("mario", "rossi", datetime.datetime(1991, 1, 25), "M", "G693") self.assertEquals(expected, actual) - def test_02_no_first_name_bug(self): - self.assertTrue(isvalid("XXXXXX77A01Z2P6B")) - - def test_03_get_birthday_format(self): + def test_02_get_birthday_format(self): self.assertEquals('02-08-23', get_birthday('MRTNTN23M02D969P')) - def test_04_unicode_handling_isvalid(self): + def test_03_unicode_handling_isvalid(self): self.assertTrue(isvalid('MRTNTN23M02D969P')) self.assertTrue(isvalid(u'MRTNTN23M02D969P')) From b4ce5bf388ba66be797f055eb9e16942766e4adb Mon Sep 17 00:00:00 2001 From: Augusto Destrero Date: Wed, 29 Jan 2014 12:47:26 +0100 Subject: [PATCH 2/2] added copyright and corrected isvalid function docstring --- codicefiscale.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codicefiscale.py b/codicefiscale.py index cbc0614..a6baee4 100644 --- a/codicefiscale.py +++ b/codicefiscale.py @@ -5,6 +5,7 @@ officially known as Italy's Codice Fiscale. Copyright (C) 2009-2013 Emanuele Rocca +Copyright (C) 2014 Augusto Destrero (support for "Omocodie" [http://it.wikipedia.org/wiki/Omocodia]) Homepage: https://github.com/ema/pycodicefiscale @@ -41,7 +42,7 @@ def isvalid(code): """``isvalid(code) -> bool`` - This function checks if the given fiscal code is syntactically valid. + This function checks if the given fiscal code is valid. eg: isvalid('RCCMNL83S18D969H') -> True isvalid('RCCMNL83S18D969') -> False