HetuTarkistus.java |
1 package kanta; 2 3 import static kanta.SisaltaaTarkistaja.*; 4 5 /** 6 * Luokka henkilötunnuksen tarkistamiseksi 7 * @author vesal 8 * @version 9.1.2011 9 * 10 */ 11 public class HetuTarkistus implements Tarkistaja { 12 /** Hetuun kelpaavat tarkistusmerkit järjestyksessä */ 13 // 0123456789012345678901234567890 14 public static final String TARKISTUSMERKIT = "0123456789ABCDEFHJKLMNPRSTUVWXY"; 15 16 /** Kuukausien maksimipituudet */ 17 // 1 2 3 4 5 6 7 8 9 10 11 12 18 public static int[] KUUKAUDET = {31,29,31,30,31,30,31,31,30,31,30,31}; 19 20 21 /** 22 * Tarkistetaan hetu. Sallitaan myös muoto jossa vain syntymäaika. 23 * @param hetu joka tutkitaan. 24 * @return null jos oikein, muuten virhettä kuvaava teksti 25 * TODO tarkistukset kuntoon myös karkausvuodesta. 26 * @example 27 * <pre name="test"> 28 * #PACKAGEIMPORT 29 * HetuTarkistus hetut = new HetuTarkistus(); 30 * hetut.tarkista("12121") === "Hetu liian lyhyt"; 31 * hetut.tarkista("k") === "Hetu liian lyhyt"; 32 * hetut.tarkista("12121k") === "Alkuosassa saa olla vain numeroita"; 33 * hetut.tarkista("121212") === null; // sallitaan pelkkä syntymäaika 34 * hetut.tarkista("001212") === "Liian pieni päivämäärä"; 35 * hetut.tarkista("321212") === "Liian suuri päivämäärä"; 36 * hetut.tarkista("300212") === "Liian suuri päivämäärä"; 37 * hetut.tarkista("310412") === "Liian suuri päivämäärä"; 38 * hetut.tarkista("121312") === "Liian suuri kuukausi"; 39 * hetut.tarkista("120012") === "Liian pieni kuukausi"; 40 * hetut.tarkista("121212B222Q") === "Väärä erotinmerkki"; 41 * hetut.tarkista("121212-2k2Q") === "Yksilöosassa kirjaimia"; 42 * hetut.tarkista("121212-2") === "Yksilöosa liian lyhyt"; 43 * hetut.tarkista("1212121") === "Väärä erotinmerkki"; 44 * hetut.tarkista("12121212") === "Väärä erotinmerkki"; 45 * hetut.tarkista("121212-") === "Yksilöosa liian lyhyt"; 46 * hetut.tarkista("121212-12345")=== "Hetu liian pitkä"; 47 * hetut.tarkista("121212-222S") === "Tarkistusmerkin kuuluisi olla N"; 48 * hetut.tarkista("121212-222N") === null; 49 * hetut.tarkista("121212-231Y") === null; 50 * hetut.tarkista("311212-2317") === null; 51 * </pre> 52 */ 53 @Override 54 public String tarkista(String hetu) { 55 int pituus = hetu.length(); 56 if ( pituus < 6 ) return "Hetu liian lyhyt"; 57 String pvm = hetu.substring(0,6); 58 if ( !onkoVain(pvm,NUMEROT)) return "Alkuosassa saa olla vain numeroita"; 59 int pv = Integer.parseInt(pvm.substring(0,2)); 60 int kk = Integer.parseInt(pvm.substring(2,4)); 61 // int vv = Integer.parseInt(pvm.substring(4,6)); TODO vielä tarkempi pvm tarkistus 62 if ( kk < 1 ) return "Liian pieni kuukausi"; 63 if ( 12 < kk ) return "Liian suuri kuukausi"; 64 int pvmkk = KUUKAUDET[kk-1]; 65 if ( pv < 1 ) return "Liian pieni päivämäärä"; 66 if ( pvmkk < pv ) return "Liian suuri päivämäärä"; 67 if ( pituus == 6 ) return null; // pelkkä syntymäaika kelpaa 68 String erotin = hetu.substring(6,7); 69 if ( !onkoVain(erotin,"+-A")) return "Väärä erotinmerkki"; 70 if ( pituus < 11 ) return "Yksilöosa liian lyhyt"; 71 if ( pituus > 11 ) return "Hetu liian pitkä"; 72 String yksilo = hetu.substring(7,10); 73 if ( !onkoVain(yksilo,NUMEROT)) return "Yksilöosassa kirjaimia"; 74 char merkki = hetunTarkistusMerkki(hetu); 75 if ( hetu.charAt(10) != merkki ) return "Tarkistusmerkin kuuluisi olla " + merkki; 76 return null; 77 } 78 79 80 /** 81 * Palauttaa mikä olisi hetun tarkistumerkki. Tuotava parametrinä 82 * laillista muotoa oleva hetu, josta mahdollisesti tarkistumerkki 83 * puuttuu. 84 * @param hetu tutkittava hetu 85 * @return hetun tarkistusmerkki 86 * @example 87 * <pre name="test"> 88 * hetunTarkistusMerkki("121212-222") === 'N'; 89 * hetunTarkistusMerkki("121212-222S") === 'N'; 90 * hetunTarkistusMerkki("121212-222N") === 'N'; 91 * hetunTarkistusMerkki("121212-231Y") === 'Y'; 92 * hetunTarkistusMerkki("311212-2317") === '7'; 93 * hetunTarkistusMerkki("311212-2317XY") === '7'; // vaikka on liikaa merkkejä 94 * hetunTarkistusMerkki("999999-9999XY") === 'F'; // vaikka on pvm väärin 95 * hetunTarkistusMerkki("12121A-222S") === 'N'; #THROWS NumberFormatException 96 * hetunTarkistusMerkki("12121A-22") === 'N'; #THROWS StringIndexOutOfBoundsException 97 * hetunTarkistusMerkki("121") === 'N'; #THROWS StringIndexOutOfBoundsException 98 * </pre> 99 */ 100 public static char hetunTarkistusMerkki(String hetu) { 101 String pvm = hetu.substring(0,6); 102 String yksilo = hetu.substring(7,10); 103 long luku = Long.parseLong(pvm+yksilo); 104 int jakojaannos = (int)(luku % 31L); 105 return TARKISTUSMERKIT.charAt(jakojaannos); 106 } 107 108 109 /** 110 * Arvotaan satunnainen kokonaisluku välille [ala,yla] 111 * @param ala arvonnan alaraja 112 * @param yla arvonnan yläraja 113 * @return satunnainen luku väliltä [ala,yla] 114 */ 115 public static int rand(int ala, int yla) { 116 double n = (yla-ala)*Math.random() + ala; 117 return (int)Math.round(n); 118 } 119 120 121 /** 122 * Arvotaan satunnainen henkilötunnus, joka täyttää hetun ehdot 123 * @return satunnainen laillinen henkilötunnus 124 */ 125 public static String arvoHetu() { 126 String apuhetu = String.format("%02d",rand(1,28)) + 127 String.format("%02d",rand(1,12)) + 128 String.format("%02d",rand(1,99)) + "-" + 129 String.format("%03d",rand(1,1000)); 130 return apuhetu + hetunTarkistusMerkki(apuhetu); 131 } 132 133 } 134