Walidacja danych: e-mail, PESEL i NIP
- Teksty i String
- poziom: średni
- aktualizacja: 15 sierpnia 2026
Formularz, który przyjmuje byle co, prędzej czy później zapcha Ci bazę śmieciami. Ten walidator sprawdza trzy dane spotykane w każdej polskiej aplikacji: e-mail, PESEL i NIP. Największa pułapka dotyczy PESEL-u — samo policzenie cyfry kontrolnej nie wystarcza, bo numer koduje też datę urodzenia, a miesiąc jest przesunięty o 20 dla roczników 2000+. Dlatego metoda czyPoprawnyPesel najpierw odtwarza datę przez LocalDate.of i odrzuca numery z nieistniejącym dniem.
import java.time.DateTimeException;
import java.time.LocalDate;
import java.util.regex.Pattern;
/**
* Walidacja polskich danych wejściowych: e-mail, PESEL, NIP — skryptyJAVA.pl
* Zapisz jako: Walidator.java
*/
public class Walidator {
private static final int[] WAGI_PESEL = {1, 3, 7, 9, 1, 3, 7, 9, 1, 3};
private static final int[] WAGI_NIP = {6, 5, 7, 2, 3, 4, 5, 6, 7};
// Praktyczny wzorzec e-maila: część lokalna, małpa, domena z kropką i literowym TLD
private static final String ZNAK_LOKALNY = "[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]";
private static final String ETYKIETA = "[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?";
private static final Pattern WZORZEC_EMAIL = Pattern.compile("^" + ZNAK_LOKALNY + "+(?:\\."
+ ZNAK_LOKALNY + "+)*@" + ETYKIETA + "(?:\\." + ETYKIETA + ")*\\.[A-Za-z]{2,}$");
/**
* Sprawdza, czy adres e-mail (może być null) ma sensowną postać: składnię, długości i domenę z kropką.
* Nie potwierdza, że skrzynka istnieje — to da tylko wysłanie wiadomości z linkiem aktywacyjnym.
*/
public static boolean czyPoprawnyEmail(String email) {
if (email == null) { return false; }
String adres = email.trim();
int malpa = adres.lastIndexOf('@');
// część lokalna: min. 1 znak, maks. 64; cały adres maks. 254 znaki
if (adres.length() > 254 || malpa < 1 || malpa > 64) { return false; }
return WZORZEC_EMAIL.matcher(adres).matches();
}
/**
* Pełna walidacja numeru PESEL: 11 cyfr, istniejąca data urodzenia i zgodna cyfra kontrolna.
* W numerze dozwolone są spacje i myślniki.
*/
public static boolean czyPoprawnyPesel(String pesel) {
String cyfry = tylkoCyfry(pesel);
if (cyfry == null || cyfry.length() != 11 || dataUrodzeniaZPesel(cyfry) == null) { return false; }
int suma = 0;
for (int i = 0; i < 10; i++) {
suma += WAGI_PESEL[i] * (cyfry.charAt(i) - '0');
}
return (10 - suma % 10) % 10 == cyfry.charAt(10) - '0';
}
/**
* Odczytuje datę urodzenia zakodowaną w numerze PESEL. Stulecie wynika z miesiąca:
* +0 = lata 1900-1999, +20 = 2000-2099, +40 = 2100-2199, +60 = 2200-2299, +80 = 1800-1899.
*
* @return data urodzenia albo null, gdy numer ma złą długość lub data nie istnieje
*/
public static LocalDate dataUrodzeniaZPesel(String pesel) {
String cyfry = tylkoCyfry(pesel);
if (cyfry == null || cyfry.length() != 11) { return null; }
int dwieCyfryRoku = Integer.parseInt(cyfry.substring(0, 2));
int zakodowanyMiesiac = Integer.parseInt(cyfry.substring(2, 4));
int dzien = Integer.parseInt(cyfry.substring(4, 6));
int rok = switch (zakodowanyMiesiac / 20) {
case 0 -> 1900 + dwieCyfryRoku;
case 1 -> 2000 + dwieCyfryRoku;
case 2 -> 2100 + dwieCyfryRoku;
case 3 -> 2200 + dwieCyfryRoku;
default -> 1800 + dwieCyfryRoku;
};
try {
return LocalDate.of(rok, zakodowanyMiesiac % 20, dzien);
} catch (DateTimeException wyjatek) {
return null; // np. 30 lutego albo miesiąc 00 czy 13
}
}
/**
* Zwraca płeć zakodowaną w numerze PESEL — decyduje 10. cyfra (parzysta = kobieta).
* Wynik to "kobieta" albo "mezczyzna", a null, gdy numer jest niepoprawny.
*/
public static String plecZPesel(String pesel) {
if (!czyPoprawnyPesel(pesel)) { return null; }
return (tylkoCyfry(pesel).charAt(9) - '0') % 2 == 0 ? "kobieta" : "mezczyzna";
}
/**
* Walidacja numeru NIP: 10 cyfr i suma kontrolna z wagami 6,5,7,2,3,4,5,6,7 modulo 11.
* W numerze dozwolone są spacje i myślniki, np. "525-244-57-67".
*/
public static boolean czyPoprawnyNip(String nip) {
String cyfry = tylkoCyfry(nip);
if (cyfry == null || cyfry.length() != 10) { return false; }
int suma = 0;
for (int i = 0; i < 9; i++) {
suma += WAGI_NIP[i] * (cyfry.charAt(i) - '0');
}
int kontrolna = suma % 11;
// reszty 10 nie da się zapisać jedną cyfrą — taki NIP po prostu nie istnieje
return kontrolna != 10 && kontrolna == cyfry.charAt(9) - '0';
}
/** Zostawia same cyfry; zwraca null, gdy tekst zawiera coś poza cyframi, spacjami i myślnikami. */
private static String tylkoCyfry(String tekst) {
if (tekst == null) { return null; }
StringBuilder wynik = new StringBuilder(tekst.length());
for (char znak : tekst.toCharArray()) {
if (znak >= '0' && znak <= '9') {
wynik.append(znak);
} else if (znak != '-' && znak != ' ') { return null; }
}
return wynik.toString();
}
// ── PRZYKŁADY ───────────────────────────────────────────
public static void main(String[] args) {
System.out.println("E-MAIL");
for (String email : new String[]{"anna.kowalska@firma.com.pl", "jan+sklep@example.org",
"bez.malpy.example.com", "dwie..kropki@example.com", "jan@localhost"}) {
System.out.printf(" %-26s -> %s%n", email, czyPoprawnyEmail(email));
}
System.out.println("PESEL");
for (String pesel : new String[]{"90051212349", "04320781539", "90051212340", "90023012345"}) {
boolean poprawny = czyPoprawnyPesel(pesel);
System.out.printf(" %-13s -> %-5s %s%n", pesel, poprawny,
poprawny ? dataUrodzeniaZPesel(pesel) + ", " + plecZPesel(pesel) : "odrzucony");
}
System.out.println("NIP");
for (String nip : new String[]{"1234563218", "525-244-57-67", "123 456 32 18", "1234567890"}) {
System.out.printf(" %-15s -> %s%n", nip, czyPoprawnyNip(nip));
}
}
}
Jak użyć tego skryptu
- Skopiuj kod i zapisz go w pliku o nazwie
Walidator.java— nazwa pliku musi być taka sama jak nazwa klasy publicznej. - Otwórz terminal w katalogu z plikiem i wpisz
java Walidator.java. Zobaczysz trzy sekcje przykładów: e-mail, PESEL i NIP, z wynikiem dla danych poprawnych i błędnych. - We własnym projekcie wywołuj metody statycznie:
Walidator.czyPoprawnyPesel(pole),Walidator.czyPoprawnyNip(pole),Walidator.czyPoprawnyEmail(pole). Wszystkie przyjmująnulli zwracają wtedyfalse. - Metody
dataUrodzeniaZPeseliplecZPeselwyciągną z numeru dodatkowe dane. Uważaj na różnicę:plecZPeselodrzuca każdy błędny numer, adataUrodzeniaZPeselcyfry kontrolnej nie liczy — dla90051212340odda 1990-05-12. Datę odczytuj dopiero poczyPoprawnyPesel.
Warto wiedzieć
- Poprawny format to jeszcze nie istniejący adresat. Że skrzynka działa, potwierdzi Ci dopiero wiadomość z linkiem aktywacyjnym, a PESEL i NIP z dobrą sumą kontrolną wygenerujesz w kilka sekund —
1111111111to poprawny NIP, jak każdy ciąg dziesięciu jednakowych cyfr. Kontrahenta sprawdzisz w wykazie podatników VAT Ministerstwa Finansów. - Wzorzec e-maila ma odsiać literówki, a nie realizować normy RFC 5322 — regexy „zgodne z RFC" mają setki znaków i tak przepuszczają adresy, których żaden serwer nie obsłuży. Stąd świadomy skutek uboczny: adres bez kropki w domenie dostaje
false, dlatego w przykładach odpadajan@localhost. Technicznie poprawny, ale w formularzu rejestracji to prawie zawsze literówka. - PESEL i data urodzenia to dane osobowe w rozumieniu RODO. Nie loguj ich do plików, nie wysyłaj w adresie URL i zbieraj tylko wtedy, gdy naprawdę są potrzebne.
- Metoda
tylkoCyfrycelowo zwracanullprzy znaku innym niż cyfra, spacja lub myślnik — dzięki temu „123abc4567" jest odrzucone, a nie po cichu okrojone do „1234567". Jeśli chcesz akceptować też kropki albo prefiksPLprzy NIP-ie, dopisz je do warunku.
Podobne skrypty
Przyjazny URL z polskich znaków
Zamienia tytuł „Żółć i Łódź!” na adres zolc-i-lodz: polskie litery rozkłada Normalizer, znaki specjalne wypadają, powtórzone separatory sklejają się w jeden, a duplikat nazwy dostaje kolejny numer.
średni Zobacz kod → Teksty i StringFormatowanie i składanie tekstu
Zestaw przykładów String.format, StringBuilder i bloków tekstu: kwoty po polsku, tabela z równymi kolumnami, skracanie zbyt długich nazw i bezpiecznie zakodowany fragment HTML.
początkujący Zobacz kod → Teksty i StringSortowanie polskich napisów (Collator)
Sortowanie i porównywanie tekstów tak, jak układa je polski alfabet: Collator zamiast String.compareTo, opcjonalne rozróżnianie wielkości liter, bezpieczna obsługa null i sortowanie rekordów po nazwisku.
średni Zobacz kod →