Sa vedem cum arata structura unui CNP:
S AA LL ZZ JJ NNN C
- S - evident, sexul. 1 pentru barbati, 2 pentru femei. Un lucru mai putin evident este ca aceasta cifra este folosita si pentru a specifica secolul sau persoane straine, in felul urmator:
- 1 si 2 - barbat sau femeie, secolul XX
- 3 si 4 - barbat sau femeie, secolul XIX
- 5 si 6 - barbat sau femeie, secolul XXI
- 7 si 8 - persoane straine rezidente in Romania - se subintelege secolul XX
- 9 - persoane straine
- AA - anul nasterii - care depinde si de prima cifra, dupa cum am specificat mai sus
- LL - luna nasterii, o valoare pe doua cifre. Poate lua valori doar intre 01 si 12
- ZZ - ziua nasterii, tot pe doua cifre. Poate lua valori intre 01 si 31, in functie de luna si an
- JJ - judetul in care a fost inregistrat CNP-ul. Poate lua valori intre 01 si 52 (nealocand niciun judet valorilor intre 47 si 50).
- NNN - dupa cate zice Wikipedia, un numar intre 1 si 999, unic per judet.
- C - cifra de control. Pentru verificare, se iau primele 12 cifre din CNP si se inmultesc cu numarul 279146358279 (cifra cu cifra) si se aduna produsele. Suma aceasta se imparte intreg cu rest la 11 - daca restul e 10, se considera 1. Daca acest rest este egal cu cifra de control, CNP-ul este (sau poate fi !) valid.
Lista oraselor o puteti gasi aici (multumesc, Daniela !) sau pe Wikipedia.
Pentru a usura (si a evita erorile) validarea CNP-urilor, am implementat o clasa care expune doar proprietati read-only. Codul a fost scris in Delphi 7 si ar trebui sa compileze corect, fara modificari, pe orice versiune mai noua de Delphi.
- unit uCNP;
- (*
- uCNP class - THE way to check for a CNP (cod numeric personal) validity in Delphi
- Instantiate an uCNP object, use "SetCNP" to set and verify a CNP and check if "ValidCNP".
- If it's valid, you can get the birthday (in a TDate format or as integers - year, month, day),
- the sex and the town encoded in the CNP.
- by DarkByte - http://www.bitcell.info
- You're allowed to use and modify this source freely, if you don't remove this notice !
- *)
- interface
- uses SysUtils, Controls, DateUtils;
- type
- TSex = (sInvalid = -1,
- sMale = 0,
- sFemale = 1);
- TCNP = class(TObject)
- private
- CNP: String;
- FValidCNP: Boolean;
- FSex: TSex;
- FYear: Word;
- FMonth: Word;
- FDay: Word;
- FBirthDay: TDate;
- FAgeInYears: Integer;
- FAgeInMinutes: Cardinal;
- Today: TDateTime;
- FTown: Byte;
- FTownName: String;
- function ContainsOnlyDigits: Boolean;
- function MatchesControlDigit: Boolean;
- function DateIsValid: Boolean;
- function IsValidCNP: Boolean;
- procedure ParseCNPData;
- published
- property ValidCNP: Boolean read FValidCNP;
- property Sex: TSex read FSex;
- property Year: Word read FYear;
- property Month: Word read FMonth;
- property Day: Word read FDay;
- property BirthDay: TDate read FBirthDay;
- property Age: Integer read FAgeInYears;
- property AgeInMinutes: Cardinal read FAgeInMinutes;
- property Town: Byte read FTown;
- property TownName: String read FTownName;
- public
- procedure SetCNP(aCNP: String; aToday: TDateTime = -1);
- end;
- const
- Judete: array [0 .. 52] of String =
- ('N/A', 'Alba', 'Arad', 'Arges', 'Bacau', 'Bihor', 'Bistrita Nasaud', 'Botosani',
- 'Brasov', 'Braila', 'Buzau', 'Caras-Severin', 'Cluj', 'Constanta', 'Covasna',
- 'Dambovita', 'Dolj', 'Galati', 'Gorj', 'Harghita', 'Hunedoara', 'Ialomita',
- 'Iasi', 'Ilfov', 'Maramures', 'Mehedinti', 'Mures', 'Neamt', 'Olt', 'Prahova',
- 'Satu Mare', 'Salaj', 'Sibiu', 'Suceava', 'Teleorman', 'Timis', 'Tulcea',
- 'Vaslui', 'Valcea', 'Vrancea', 'Bucuresti', 'Bucuresti S1', 'Bucuresti S2',
- 'Bucuresti S3', 'Bucuresti S4', 'Bucuresti S5', 'Bucuresti S6',
- '-', '-', '-', '-', 'Calarasi', 'Giurgiu');
- SexType: array [TSex] of String = ('N/A', 'Masculin', 'Feminin');
- implementation
- const
- PCP: array [1 .. 12] of Byte = (2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9);
- Months: array [1 .. 12] of Byte = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
- procedure TCNP.SetCNP(aCNP: String; aToday: TDateTime = -1);
- begin
- CNP := aCNP;
- if (aToday <> -1)
- then Today := aToday
- else Today := NOW;
- FValidCNP := IsValidCNP;
- if not FValidCNP then
- begin
- FSex := sInvalid;
- FYear := 0;
- FMonth := 0;
- FDay := 0;
- FBirthDay := 0;
- FAgeInYears := -1;
- FAgeInMinutes := 0;
- FTown := 0;
- FTownName := Judete[0];
- end;
- end;
- function TCNP.ContainsOnlyDigits: Boolean;
- var
- lIndex: Integer;
- begin
- Result := True;
- if (Length(CNP) <> 13) then
- begin
- Result := False;
- Exit;
- end;
- for lIndex := 1 to 13 do
- begin
- if (Ord(CNP[lIndex]) < 48) and (Ord(CNP[lIndex]) > 57) then
- begin
- Result := False;
- Break;
- end;
- end;
- end;
- function TCNP.MatchesControlDigit: Boolean;
- var
- lIndex: Integer;
- lSuma, lRest: Word;
- begin
- lSuma := 0;
- for lIndex := 1 to 12 do
- lSuma := lSuma + (Ord(CNP[lIndex]) - 48) * PCP[lIndex];
- lRest := lSuma mod 11;
- if (lRest = 10) then
- lRest := 1;
- Result := (Chr(lRest + 48) = CNP[13]);
- end;
- function TCNP.DateIsValid: Boolean;
- var
- lLeapYear: Boolean;
- begin
- Result := True;
- FYear := 1900 + StrToInt(Copy(CNP, 2, 2));
- case CNP[1] of
- '3', '4': Dec(FYear, 100);
- '5', '6': Inc(FYear, 100);
- end;
- lLeapYear := IsInLeapYear(FYear);
- FMonth := StrToInt(Copy(CNP, 4, 2));
- FDay := StrToInt(Copy(CNP, 6, 2));
- FTown := StrToInt(Copy(CNP, 8, 2));
- if (lLeapYear and (months[FMonth] < FDay) and (FMonth <> 2) and (FDay <> 29))
- then Result := False
- else FBirthDay := EncodeDate(FYear, FMonth, FDay);
- end;
- procedure TCNP.ParseCNPData;
- begin
- if Odd(StrToInt(CNP[1]))
- then FSex := sMale
- else FSex := sFemale;
- FTown := StrToInt(Copy(CNP, 8, 2));
- FTownName := Judete[FTown];
- FAgeInYears := YearsBetween(FBirthDay, Today);
- FAgeInMinutes := MinutesBetween(FBirthDay, Today);
- end;
- function TCNP.IsValidCNP: Boolean;
- begin
- Result := ContainsOnlyDigits and MatchesControlDigit and DateIsValid;
- if Result then
- ParseCNPData;
- end;
- end.
Un program demonstrativ (sursa si executabil) care foloseste aceasta clasa poate fi gasit in atasament - vedeti screenshot-ul atasat:

Bafta !
Welcome to BitCell. Click here to register !
). Este ok.
Pai da. Mult mai elegant si corect.