…meie igapäevast IT’d anna meile igapäev…

2008-03-11

Eesti isikukoodi valideerimine .NET’is

Filed under: ID-kaart,Programmeerimine — Sander @ 10:12:45
Tags: , ,

ID validator Oli vaja valideerida Eesti isikukoode, aga ei leidnud C#/.NET koodi selle jaoks. Küll aga leidsin Delphi koodi – http://toom.wordpress.com/2007/01/07/testing-estonian-national-identification-number-isikukood/. Pole ju suur asi see ümber konvertida – nii kirjutasingi kiirelt meetodi ID-koodi valideerimiseks C#’s. Kood on toodud ära allpool, muidugimõista on kogu kood copyleft, võiksid küll kommentaari kirjutada kui seda kusagil kasutasid.

Kui näed valideerimises viga, siis teata, teen parandused.

Kirjutasin ka pisikese .NET 2.0 desktopirakenduse, mis ka veidi rohkem infot näitab (sugu, sünnipäev, vea korral ka põhjus). Selle saad tõmmata siit – ainult .exe, ei installerit ega dokumentatsiooni, 22KB.

Kui kunagi viitsin, siis teen ka pisikese JavaScripti-põhise valideerija. Selleks ka paar kasulikku linki isikukoodi kohta:

http://et.wikipedia.org/wiki/Isikukood

http://www.riigiteataja.ee/ert/act.jsp?id=983873&searchCurrent


   private bool validateIDCode(string idCode)
        {
            try
            {
                // check length
                if (idCode.Length != 11) return false;

                int century = 0;

                // check century
                switch (idCode[0])
                {
                    case '1':
                    case '2':
                        {
                            century = 1800;
                            break;
                        }
                    case '3':
                    case '4':
                        {
                            century = 1900;
                            break;
                        }
                    case '5':
                    case '6':
                        {
                            century = 2000;
                            break;
                        }
                    default:
                        {
                            return false;
                        }
                }


                // check if birthday is a valid date
                // get a date from IK
                string s = idCode.Substring(5, 2) + "." +
                    idCode.Substring(3, 2) + "." +
                    Convert.ToString(century + Convert.ToInt32(idCode.Substring(1, 2)));

                //error if parse fails, catch gets false. TryParse() does not exist in .NET 1.1
                DateTime d = DateTime.Parse(s);

                // calculate the checksum
                int n = Int16.Parse(idCode[0].ToString()) * 1
                      + Int16.Parse(idCode[1].ToString()) * 2
                      + Int16.Parse(idCode[2].ToString()) * 3
                      + Int16.Parse(idCode[3].ToString()) * 4
                      + Int16.Parse(idCode[4].ToString()) * 5
                      + Int16.Parse(idCode[5].ToString()) * 6
                      + Int16.Parse(idCode[6].ToString()) * 7
                      + Int16.Parse(idCode[7].ToString()) * 8
                      + Int16.Parse(idCode[8].ToString()) * 9
                      + Int16.Parse(idCode[9].ToString()) * 1;

                int c = n % 11;

                // special case recalculate the checksum
                if (c == 10)
                {
                    // calculate the checksum
                    n = Int16.Parse(idCode[0].ToString()) * 3
                      + Int16.Parse(idCode[1].ToString()) * 4
                      + Int16.Parse(idCode[2].ToString()) * 5
                      + Int16.Parse(idCode[3].ToString()) * 6
                      + Int16.Parse(idCode[4].ToString()) * 7
                      + Int16.Parse(idCode[5].ToString()) * 8
                      + Int16.Parse(idCode[6].ToString()) * 9
                      + Int16.Parse(idCode[7].ToString()) * 1
                      + Int16.Parse(idCode[8].ToString()) * 2
                      + Int16.Parse(idCode[9].ToString()) * 3;

                    c = n % 11;
                    c = c % 10;
                }

                return (c == Int16.Parse(idCode[10].ToString()));
            }

            catch
            {
                return false;
            }
        }

17 kommentaari »

  1. Ei pääse kiusatusest esitada kood, mis kogu kontrollnumbri arvutab ilma tüütu korrutamiseta, mod 11 on tõsi küll vältimatu.

    Kuna vaevalt et seda keegi nüüd rakendab, siis ümber kirjutama moodsatesse keeltesse ei hakka, koodist ei loe ka välja ilma väikse nikerdamiseta, mis algne algoritm IK jaoks üldse oligi.
    Fox kood selle asja jaoks on selline:
    (loodetavasti loetav, koodi eesmärk on viidata, et asi taandub ikkagi kõige tavalisemale kontrollsummale, täpsemini kontroll-“summasummale”,
    mis viitab sellele, et see kontrolsumma võinuks olla suuremate probleemideta primitiivne numbrite summa ja siis mod 11, nagu ISBN-s ongi.
    )

    PROCEDURE ikcnum
    * Eesti isikukoodi kontollarvu arvutamine:
    PARAMETERS mik && Isikukood stringina.
    PRIVATE msum,msum1,mi,mlopp
    STORE 0 TO msum,msum1
    mi=3
    DO WHILE mi<12
    msum=msum+ASC(RIGHT(mik,mi))
    msum1=msum1+msum
    mi=mi+1
    ENDDO
    mlopp=ASC(RIGHT(mik,2))
    msum1=msum1+mlopp+3
    msum1=MOD(msum1,11)
    IF msum1#10
    RETURN msum1
    ELSE
    msum=msum+mlopp+ASC(RIGHT(mik,3))+ASC(RIGHT(mik,4))
    msum=MOD(msum+msum+2,11)
    RETURN IIF(msum#10,msum,0)
    ENDIF
    *******************************************

    kommentaar kirjutas Sekeldaja — 2008-03-11 @ 10:59:22 | Vasta

  2. Vähemalt exe failis on sul kusagil viga sees. Pole end kunagi naisena tundnud aga see validaator väidab et ma ikkagi olen naine.

    kommentaar kirjutas Mairo — 2008-03-11 @ 11:54:18 | Vasta

  3. Jah, kogamata oli näpukas sisse sattunud – % 2 == 0, mitte % != 0. Tänan, parandasin.

    kommentaar kirjutas dukelupus — 2008-03-11 @ 12:04:43 | Vasta

  4. No aga võiks orgunnida siis miski võistluse, millises keeles ja kelle koostatuna näeks isikukoodi valideerimine vahvam välja. Esitan ka ühe variandi, 3 tugrikut sellele, kes arvab, mis keelega on tegu :-p

    FUNCTION zkontrolli_isikukoodi.
    *”———————————————————————-
    *”*”Local Interface:
    *” IMPORTING
    *” VALUE(KOOD) TYPE CHAR11
    *” EXPORTING
    *” REFERENCE(CORRECT) TYPE CHAR1
    *” VALUE(SUGU) TYPE ANREX
    *” VALUE(SYNNA) TYPE GBDAT
    *”———————————————————————-

    DATA:
    a TYPE i,
    b TYPE i,
    c TYPE i,
    d TYPE i,
    e TYPE i,
    f TYPE i,
    g TYPE i,
    h TYPE i,
    i TYPE i,
    j TYPE i,
    jark TYPE i,
    summa TYPE i,
    n,
    len TYPE i,
    aasta(2),
    kuu(2),
    paev(2),
    uuskood(11),
    bdpref(2).

    aasta = kood+1(2).
    kuu = kood+3(2).
    paev = kood+5(2).

    len = STRLEN( kood ).

    IF len NE 11.
    correct = ‘ ‘.
    EXIT.
    ENDIF.

    n = kood(1). MOVE n TO a.
    n = kood+1(1). MOVE n TO b.
    n = kood+2(1). MOVE n TO c.
    n = kood+3(1). MOVE n TO d.
    n = kood+4(1). MOVE n TO e.
    n = kood+5(1). MOVE n TO f.
    n = kood+6(1). MOVE n TO g.
    n = kood+7(1). MOVE n TO h.
    n = kood+8(1). MOVE n TO i.
    n = kood+9(1). MOVE n TO j.

    CASE a.
    WHEN ‘1’.
    sugu = ‘M’.
    bdpref = ’18’.
    WHEN ‘3’.
    sugu = ‘M’.
    bdpref = ’19’.
    WHEN ‘5’.
    sugu = ‘M’.
    bdpref = ’20’.
    WHEN ‘2’.
    sugu = ‘F’.
    bdpref = ’18’.
    WHEN ‘4’.
    sugu = ‘F’.
    bdpref = ’19’.
    WHEN ‘6’.
    sugu = ‘F’.
    bdpref = ’20’.
    WHEN OTHERS.
    correct = ‘ ‘.
    EXIT.
    ENDCASE.

    CONCATENATE bdpref aasta kuu paev INTO synna.

    CALL FUNCTION ‘HRIQ_CHECK_DATE_BAPI’
    EXPORTING
    iv_date = synna
    EXCEPTIONS
    date_invalid = 1
    date_initial = 2
    OTHERS = 3.
    IF sy-subrc 0.
    correct = ‘ ‘.
    EXIT.
    ENDIF.

    summa = a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + g * 7 + h * 8 + i * 9 + j * 1.

    COMPUTE jark = summa mod 11.
    IF jark = 10.
    summa = a * 3 + b * 4 + c * 5 + d * 6 + e * 7 + f * 8 + g * 9 + h * 1 + i * 2 + j * 3.
    COMPUTE jark = summa mod 11.
    ENDIF.
    IF jark = 10.
    jark = 0.
    ENDIF.
    MOVE jark TO n.
    CONCATENATE kood(10) n INTO uuskood.

    IF uuskood EQ kood.
    correct = ‘X’.
    ELSE.
    correct = ‘ ‘.
    ENDIF.

    ENDFUNCTION.

    kommentaar kirjutas Muidumeez — 2008-03-11 @ 13:19:23 | Vasta

  5. Mu esimene pakkumine oli mingi VBA-sarnane või mõni muu Basic. Aga paari märksõna kiire googeldamine nagu viitaks et tegemist on SAP’i ABAP’iga?

    kommentaar kirjutas dukelupus — 2008-03-11 @ 14:02:24 | Vasta

  6. Õige, dukeplus, tegu on ABAP-iga, kolm tugrikut on sinu :-)

    kommentaar kirjutas muidumeez — 2008-03-11 @ 14:16:53 | Vasta

  7. Kas algset koodi ei võiks lihtsalt false tagastamiselt, mis on küllaltki omane mitte-OO keeltele, viia üle exceptionite peale? Sel teel saaks koodi tasemel teada juba konkreetse põhjuse, miks valideerimine ebaõnnestus.

    kommentaar kirjutas Gunnar — 2008-03-11 @ 16:02:25 | Vasta

  8. Ikka saab. Aga seda polnud antud juhul vaja – ja ma tegin üsna 1:1 tõlke Delphi koodist.

    kommentaar kirjutas dukelupus — 2008-03-11 @ 16:38:53 | Vasta

  9. Need kellel arvutis ühtegi keelt ei ela või serverit ei jookse, peavad selle FF aadressiribale sisse toksima:
    javascript: var check=0, i=0;var kood=prompt(“Teie isikukood:”);if (kood!=null && kood!=””){if (kood.length!=11) exit;var dat = new Date(kood.substr(1,2),kood.substr(3,2),kood.substr(5,2));if(dat.getYear()!=kood.substr(1,2) || dat.getMonth()!= kood.substr(3,2) || dat.getDate()!=kood.substr(5,2)) exit;if (kood[0]6) exit;while (i<9){check += kood[i]*(i+1);i++;}check += kood[9]*1;if(check % 11 < 10){ if (check % 11==kood[10]) alert(“Klapib!”);}else{i = 0;check = 0;while (i<7){check += kood[i]*(i+3);i++;}check = check*1 + kood[7]*1 + kood[8]*2 + kood[9]*3;if ((check % 11 < 10 && check % 11==kood[10]) || (check % 11 == 10 && 0==kood[10])) alert(“Klapib!”);}}

    kommentaar kirjutas oliver — 2008-03-11 @ 17:59:05 | Vasta

  10. silli mii… osa koodi loomulikult haihtus. Aga keda see javascript üldse huvitakski…

    kommentaar kirjutas oliver — 2008-03-11 @ 18:15:45 | Vasta

  11. Aga keegi lolcode’i ei viitsi seda ümber kribada? :D Endal jääb oskustest vajaka :D

    kommentaar kirjutas mks — 2008-03-11 @ 18:15:49 | Vasta

  12. Oliver: pane <code>… </code> vahele. Tõsi küll, br pead realõppudesse panema ka. Kahjuks wordpress mingil idiootsel põhjustel kommentaarides pre’d ei luba.

    kommentaar kirjutas dukelupus — 2008-03-11 @ 19:09:14 | Vasta

  13. Ei saa märkimata jätta, et eestis arvutatakse ka juriidilistele isikutele antavate registrikoodide kontrolljärke sama algoritmiga.
    Teil enamus arvutusi väga isikukoodipõhised.

    kommentaar kirjutas wiinanina — 2008-03-11 @ 21:40:40 | Vasta

  14. Koodinäide Lispis:

    (defun valid-date (year month day)
    “Kontrollib kas tegu on korrektse kuupäevaga”
    (integerp ;; tegelikult peaks töötama edukalt ka ilma selleta
    (ignore-errors
    (encode-universal-time 0 0 0 day month year 0))))

    (defun valid-birth-date (isikukood)
    (let ((sajand
    (case (char isikukood 0)
    ((#\1 #\2) 1800)
    ((#\3 #\4) 1900)
    ((#\5 #\6) 2000))))
    (when sajand
    (valid-date
    (+ sajand (parse-integer (subseq isikukood 1 3)))
    (parse-integer (subseq isikukood 3 5))
    (parse-integer (subseq isikukood 5 7))))))

    (defun string+ (&rest parts)
    (with-output-to-string (out)
    (dolist (part parts)
    (write part :stream out :escape nil))))

    (defun initial-checksum (isikukood fn)
    (mod
    (loop for n from 1 to 10
    sum (* (1+ (mod (funcall fn n) 9))
    (parse-integer (string+ (char isikukood (1- n))))))
    11))

    (defun ik-checksum (isikukood)
    (let ((temp-checksum (initial-checksum isikukood ‘1-)))
    (if (= 10 temp-checksum)
    (mod (initial-checksum isikukood ‘1+) 10)
    temp-checksum)))

    (defun valid-checksum (isikukood)
    (= (parse-integer (string+ (char isikukood (1- (length isikukood))))) ; last digit
    (ik-checksum isikukood)))

    (defun valid-isikukood (isikukood)
    (and
    (= (length isikukood) 11) ;peab sisaldama 11 numbrit
    (valid-birth-date isikukood)
    (valid-checksum isikukood)))

    kommentaar kirjutas Lauri — 2008-03-15 @ 14:44:23 | Vasta

  15. veel üks c# variant, selline mis käib numbrite mitte stringide peal ning ei eelda rakenduse et-EE contextis jooksutamist :P

    public static DateTime? ParsePersonalCode(string code)
    {
    DateTime? res = null;
    ulong l;
    if(code != null && code.Length == 11 && ulong.TryParse(code, NumberStyles.None, NumberFormatInfo.InvariantInfo, out l)
    && l >= 10001010000 && l = 1 && d = 1 && m <= 12)
    try
    {
    res = new DateTime((int)((i /= 100) % 100 + (18 + (i – 100) / 200) * 100), (int)m, (int)d);
    }
    catch(ArgumentException)
    {
    }
    }
    return res;
    }

    static uint CalculateControlCode(uint multiply, ulong code)
    {
    uint n = 0;
    for(uint i = 10;i != 0;i–)
    {
    uint m = i + multiply;
    n += (uint)(code % 10) * (m <= 9 ? m : m – 9);
    code /= 10;
    }
    return n % 11;
    }

    kommentaar kirjutas Pent — 2008-03-23 @ 01:19:43 | Vasta

  16. nojah… wordpress pistis paraja portsu funktsioonist nahka… niipalju siis sellest…

    kommentaar kirjutas Pent — 2008-03-23 @ 01:22:54 | Vasta

  17. […] Kunagi sai ka kirjutatud isikukoodi valideerimisest .NET’is, loe siit. […]

    Pingback-viide kirjutas Eesti isikukoodi valideerimine JavaScriptis « …meie igapäevast IT’d anna meile igapäev… — 2010-04-05 @ 12:18:27 | Vasta


RSS feed for comments on this post. TrackBack URI

Lisa kommentaar

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Muuda )

Twitter picture

You are commenting using your Twitter account. Log Out / Muuda )

Facebook photo

You are commenting using your Facebook account. Log Out / Muuda )

Google+ photo

You are commenting using your Google+ account. Log Out / Muuda )

Connecting to %s

Blog at WordPress.com.