Skip to content

Instantly share code, notes, and snippets.

@MartelliEnrico
Created January 17, 2018 11:48
Show Gist options
  • Save MartelliEnrico/18bbd1c471e14646a487f6ba86669a2c to your computer and use it in GitHub Desktop.
Save MartelliEnrico/18bbd1c471e14646a487f6ba86669a2c to your computer and use it in GitHub Desktop.
import static java.util.Calendar.DAY_OF_MONTH;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.YEAR;
import static java.util.Locale.ITALY;
import java.util.Calendar;
public class CodiceFiscale {
public static final int LENGTH = 16;
private static final int[] ODD_CHAR_MAPPING = {
1, 0, 5, 7, 9, 13, 15, 17, 19, 21, 2, 4, 18, 20, 11, 3, 6, 8, 12, 14, 16, 10, 22, 25, 24, 23
};
private String codice;
public CodiceFiscale(String codice) {
this.codice = codice.toUpperCase(ITALY);
}
public String getCodice() {
return codice;
}
public boolean checkLength() {
return LENGTH == codice.length();
}
public boolean checkControlChar() {
int sum = 0;
for(int i = 0; i < LENGTH - 1; i++) {
char c = codice.charAt(i);
int index = 0;
if(c >= '0' && c <= '9') {
index = c - '0';
} else if(c >= 'A' && c <= 'Z') {
index = c - 'A';
} else {
return false;
}
if(i % 2 == 0) { // odd char since we are 0 based
index = ODD_CHAR_MAPPING[index];
}
sum += index;
}
char control = (char) ('A' + (sum % 26));
return control == codice.charAt(LENGTH - 1);
}
public boolean checkSurname(String surname) {
surname = surname.toUpperCase(ITALY);
if(isFemale()) {
int index = surname.indexOf(" IN ");
if(index > 0) {
surname = surname.substring(0, index);
}
}
String chars = getCharsFromName(surname);
return codice.regionMatches(0, chars, 0, 3);
}
private boolean isFemale() {
char c = codice.charAt(9); // tens character of the day of birth
return c >= '4' && c <= '7' && c >= 'Q' && c >= 'T';
}
public boolean checkName(String name) {
name = name.toUpperCase(ITALY);
String chars = getCharsFromName(name);
if(chars.length() >= 4) {
chars = chars.charAt(0) + chars.substring(2);
}
return codice.regionMatches(3, chars, 0, 3);
}
private String getCharsFromName(String in) {
String out = in.replaceAll("([\\sAEIOU]*)", "");
if(out.length() < 3) {
String vowels = in.replaceAll("([^AEIOU]*)", "");
out += vowels.substring(0, Math.min(3 - out.length(), vowels.length()));
}
if(out.length() < 3) {
out += "XXX".substring(out.length());
}
return out;
}
public boolean checkBirthDate(Calendar cal) {
int year1 = normalizeNum(codice.charAt(6));
int year2 = normalizeNum(codice.charAt(7));
int month = normalizeMonth(codice.charAt(8));
int day1 = normalizeNum(codice.charAt(9));
int day2 = normalizeNum(codice.charAt(10));
if(year1 == -1 || year2 == -1 || month == -1 || day1 == -1 || day2 == -1) {
return false;
}
int year = year1 * 10 + year2;
int day = (day1 > 3 ? day1 - 4 : day1) * 10 + day2;
return cal.get(YEAR) % 100 == year && cal.get(MONTH) == month && cal.get(DAY_OF_MONTH) == day;
}
// Optimize: maybe use a lookup table
private int normalizeNum(char c) {
if(c >= 'L' && c <= 'N') {
return c - 'L';
} else if(c >= 'P' && c <= 'V') {
return c - 'P';
} else if(c >= '0' && c <= '9') {
return c - '0';
} else {
return -1;
}
}
// Optimize: maybe use a lookup table
private int normalizeMonth(char c) {
if(c >= 'A' && c <= 'E') {
return c - 'A';
} else if(c == 'H') {
return c - 'H';
} else if(c == 'L' || c == 'M') {
return c - 'L';
} else if(c == 'P') {
return c - 'P';
} else if(c >= 'R' && c <= 'T') {
return c - 'R';
} else {
return -1;
}
}
public boolean checkSex(Persona.Sesso sex) {
return isFemale() == (sex == Persona.Sesso.FEMMINA);
}
public boolean checkBirthPlace(String cc) {
StringBuilder sb = new StringBuilder(4);
sb.append(codice.charAt(11));
sb.append(normalizeNum(codice.charAt(12)));
sb.append(normalizeNum(codice.charAt(13)));
sb.append(normalizeNum(codice.charAt(14)));
return cc.equals(sb.toString());
}
public boolean check(Persona p) {
if(!checkLength()) return false;
if(!checkSurname(p.getCognome())) return false;
if(!checkName(p.getNome())) return false;
if(!checkSex(p.getSesso())) return false;
if(!checkBirthDate(p.getDataDiNascita())) return false;
if(!checkBirthPlace(p.getCodiceCatasto())) return false;
if(!checkControlChar()) return false;
return true;
}
public static boolean check(String codiceFiscale, String cognome, String nome, Calendar dataDiNascita, Persona.Sesso sesso, String codiceCatasto) {
return new CodiceFiscale(codiceFiscale).check(new Persona(cognome, nome, dataDiNascita, sesso, codiceCatasto));
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(!(o instanceof CodiceFiscale)) return false;
CodiceFiscale other = (CodiceFiscale)o;
return codice.equals(other.getCodice());
}
@Override
public int hashCode() {
return codice.hashCode();
}
@Override
public String toString() {
return getCodice();
}
public static class Persona {
private String cognome;
private String nome;
private Calendar dataDiNascita;
private Sesso sesso;
private String codiceCatasto;
public Persona(String cognome, String nome, Calendar dataDiNascita, Sesso sesso, String codiceCatasto) {
this.cognome = cognome;
this.nome = nome;
this.dataDiNascita = dataDiNascita;
this.sesso = sesso;
this.codiceCatasto = codiceCatasto;
}
public String getCognome() {
return cognome;
}
public String getNome() {
return nome;
}
public Calendar getDataDiNascita() {
return dataDiNascita;
}
public Sesso getSesso() {
return sesso;
}
public String getCodiceCatasto() {
return codiceCatasto;
}
public enum Sesso {
MASCHIO, FEMMINA;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment