Walidacja i czyszczenie tekstu w Pythonie to jeden z podstawowych etapów automatyzacji pracy z danymi. Jeśli pobierasz dane z formularzy, API, plików CSV, Excela, PDF-ów albo systemów CRM, musisz liczyć się z błędami: dodatkowymi spacjami, pustymi wartościami, złym formatem e-maila, nietypowymi znakami, duplikatami lub tekstem zapisanym w różnych standardach.
Nieoczyszczony tekst może powodować błędy w raportach, wyszukiwaniu, analizie danych, integracjach API i bazach danych. Dlatego przed dalszym przetwarzaniem warto wykonać normalizację, walidację i kontrolę jakości danych tekstowych.
W tym artykule zobaczysz praktyczne przykłady czyszczenia tekstu w Pythonie: podstawową normalizację, walidację przez regex, sprawdzanie e-maili, telefonów i NIP-ów, wykrywanie anomalii, normalizację Unicode oraz proste reguły jakości tekstu.
Kurs Python od podstaw — PyStart
Zacznij programować w Pythonie od zera. Praktyczny kurs wideo z ćwiczeniami — bez wcześniejszego doświadczenia.
- ✓24 lekcje wideo + 80 ćwiczeń
- ✓Realne bazy z e-commerce
- ✓Społeczność i code-review
Kiedy warto walidować i czyścić tekst?
Czyszczenie tekstu przydaje się zawsze wtedy, gdy dane pochodzą od użytkowników lub z zewnętrznych systemów. Takie dane rzadko są idealne. Czasem zawierają literówki, złe formaty, niewidoczne znaki albo przypadkowe spacje.
Najczęstsze zastosowania walidacji tekstu w Pythonie to:
- czyszczenie danych z formularzy kontaktowych,
- walidacja adresów e-mail i numerów telefonu,
- normalizacja danych klientów,
- sprawdzanie NIP, kodów pocztowych i identyfikatorów,
- przygotowanie tekstu do raportów,
- oczyszczanie danych z Excela lub CSV,
- przetwarzanie tekstu wyciągniętego z PDF,
- przygotowanie danych do importu do CRM lub bazy danych,
- wykrywanie pustych, zbyt krótkich lub podejrzanych wpisów.
Dobrze przygotowana walidacja ogranicza błędy na późniejszych etapach automatyzacji.
Podstawowe czyszczenie tekstu w Pythonie
Najprostsze czyszczenie tekstu obejmuje usunięcie spacji z początku i końca, normalizację białych znaków oraz opcjonalne usunięcie niechcianych znaków specjalnych.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20import re def clean_text(text: str | None) -> str: """Podstawowe czyszczenie tekstu.""" if not text: return "" # Usuwanie spacji z początku i końca text = text.strip() # Zamiana wielu spacji, tabów i nowych linii na jedną spację text = re.sub(r"\s+", " ", text) # Opcjonalne usunięcie wybranych znaków specjalnych text = re.sub(r"[^\w\sąćęłńóśźżĄĆĘŁŃÓŚŹŻ-]", "", text) return text print(clean_text(" To jest \n przykładowy tekst!!! "))
Wynik:
1To jest przykładowy tekst
To dobry pierwszy krok przy danych pochodzących z formularzy, arkuszy kalkulacyjnych i plików tekstowych.
Normalizacja białych znaków
Białe znaki to nie tylko zwykłe spacje. Mogą to być także tabulatory, znaki nowej linii albo niewidoczne odstępy skopiowane z dokumentów. W automatyzacji często warto ujednolicić je do jednej spacji.
Python1 2 3 4 5 6 7 8 9 10 11 12import re def normalize_whitespace(text: str | None) -> str: """Normalizuje białe znaki w tekście.""" if not text: return "" return re.sub(r"\s+", " ", text).strip() text = "Jan\tKowalski\n\nWarszawa Polska" print(normalize_whitespace(text))
Taka funkcja jest prosta, ale bardzo często rozwiązuje realne problemy w danych tekstowych.
Walidacja tekstu przez regex
Regex, czyli wyrażenia regularne, pozwala sprawdzać, czy tekst pasuje do określonego wzorca. To wygodne przy walidacji e-maili, telefonów, kodów pocztowych, identyfikatorów i numerów dokumentów.
Walidacja adresu e-mail
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16import re def validate_email(email: str) -> bool: """Sprawdza, czy adres e-mail ma poprawny format.""" if not email: return False email = email.strip() pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" return bool(re.fullmatch(pattern, email)) print(validate_email("jan@example.com")) print(validate_email("jan.example.com"))
Ten regex wystarczy do typowej walidacji biznesowej. Pełna walidacja e-maili zgodna ze wszystkimi wyjątkami standardu jest dużo bardziej złożona, ale w większości automatyzacji nie jest potrzebna.
Walidacja numeru telefonu
Poniższy przykład sprawdza polski numer telefonu w formacie z opcjonalnym prefiksem +48.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17import re def validate_polish_phone(phone: str) -> bool: """Waliduje polski numer telefonu.""" if not phone: return False cleaned = re.sub(r"[\s-]", "", phone) pattern = r"^(\+48)?\d{9}$" return bool(re.fullmatch(pattern, cleaned)) print(validate_polish_phone("+48 123 456 789")) print(validate_polish_phone("123-456-789")) print(validate_polish_phone("12345"))
Przed walidacją usuwamy spacje i myślniki, bo użytkownicy często wpisują numer w różnych formatach.
Walidacja kodu pocztowego
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14import re def validate_postal_code(code: str) -> bool: """Waliduje polski kod pocztowy w formacie XX-XXX.""" if not code: return False pattern = r"^\d{2}-\d{3}$" return bool(re.fullmatch(pattern, code.strip())) print(validate_postal_code("00-001")) print(validate_postal_code("00001"))
Walidacja NIP w Pythonie
NIP wymaga nie tylko sprawdzenia długości i cyfr, ale też sumy kontrolnej. To dobry przykład walidacji, której nie da się wykonać samym prostym regexem.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22def validate_nip(nip: str) -> bool: """Waliduje polski NIP na podstawie sumy kontrolnej.""" if not nip: return False nip = nip.replace("-", "").replace(" ", "") if not nip.isdigit() or len(nip) != 10: return False weights = [6, 5, 7, 2, 3, 4, 5, 6, 7] checksum = sum(int(nip[i]) * weights[i] for i in range(9)) control_digit = checksum % 11 if control_digit == 10: return False return control_digit == int(nip[9]) print(validate_nip("123-456-32-18")) print(validate_nip("1234563218"))
W automatyzacji biznesowej taka walidacja przydaje się przy imporcie kontrahentów, faktur i danych firmowych.
Normalizacja tekstu Unicode
Tekst może zawierać różne warianty znaków, akcenty, nietypowe spacje i znaki kopiowane z dokumentów. Moduł unicodedata pozwala ujednolicić zapis.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23import re import unicodedata def normalize_text(text: str | None, remove_accents: bool = False) -> str: """Normalizuje tekst Unicode i białe znaki.""" if not text: return "" text = unicodedata.normalize("NFKC", text) text = re.sub(r"\s+", " ", text).strip() if remove_accents: text = unicodedata.normalize("NFD", text) text = "".join( char for char in text if unicodedata.category(char) != "Mn" ) return text.lower() print(normalize_text(" Café résumé ", remove_accents=True)) print(normalize_text(" Zażółć gęślą jaźń ", remove_accents=False))
Usuwanie akcentów może być przydatne przy wyszukiwaniu lub porównywaniu tekstów, ale w danych polskich często lepiej zachować znaki diakrytyczne.
Normalizacja polskiego tekstu
W polskich danych zwykle chcesz zachować znaki takie jak ą, ę, ł, ń, ó, ś, ź, ż. Wtedy normalizacja powinna skupiać się głównie na spacjach, wielkości liter i znakach niewidocznych.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16import re def normalize_polish_text(text: str | None) -> str: """Normalizuje polski tekst bez usuwania znaków diakrytycznych.""" if not text: return "" text = text.strip() text = re.sub(r"\s+", " ", text) text = text.replace("\u00a0", " ") # twarda spacja text = re.sub(r"\s+", " ", text) return text print(normalize_polish_text(" To jest\u00a0tekst z odstępami. "))
Twarda spacja często pojawia się w danych kopiowanych ze stron internetowych, PDF-ów i dokumentów biurowych.
Wykrywanie anomalii w tekście
Python co tydzień — newsletter dla programistów
Otrzymuj codzienne ćwiczenia, ciekawostki z ekosystemu Pythona i wskazówki do rozmów rekrutacyjnych.
Anomalie tekstowe to wartości, które odstają od reszty danych. Mogą być puste, podejrzanie krótkie, bardzo długie albo zawierać nietypowe znaki.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42def detect_text_anomalies(texts: list[str]) -> dict[str, list[int]]: """Wykrywa podstawowe anomalie w liście tekstów.""" anomalies = { "puste": [], "za_krotkie": [], "za_dlugie": [], "nietypowe_znaki": [] } normalized_texts = [text or "" for text in texts] lengths = [len(text.strip()) for text in normalized_texts if text.strip()] avg_length = sum(lengths) / len(lengths) if lengths else 0 for index, text in enumerate(normalized_texts): stripped = text.strip() if not stripped: anomalies["puste"].append(index) continue if avg_length and len(stripped) < avg_length * 0.3: anomalies["za_krotkie"].append(index) if avg_length and len(stripped) > avg_length * 3: anomalies["za_dlugie"].append(index) if any(not char.isprintable() for char in stripped): anomalies["nietypowe_znaki"].append(index) return anomalies texts = [ "Normalny tekst", "", "A", "Bardzo długi tekst " * 100, "Tekst z \x00 znakiem kontrolnym" ] print(detect_text_anomalies(texts))
To prosty mechanizm kontroli jakości. Możesz go rozbudować o własne reguły, np. wykrywanie HTML, emoji, zbyt wielu cyfr albo tekstów pisanych wielkimi literami.
Usuwanie HTML z tekstu
Dane z API i formularzy czasem zawierają fragmenty HTML. Jeśli nie chcesz ich dalej przetwarzać, możesz je usunąć.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15import re def remove_html_tags(text: str | None) -> str: """Usuwa tagi HTML z tekstu.""" if not text: return "" text = re.sub(r"<[^>]+>", " ", text) text = re.sub(r"\s+", " ", text).strip() return text html = "<p>To jest <strong>ważny</strong> tekst.</p>" print(remove_html_tags(html))
Do prostych przypadków regex wystarczy. Przy bardziej złożonym HTML lepiej użyć parsera, np. BeautifulSoup.
Szybkie reguły jakości tekstu
Kurs Python dla początkujących — PyStart
Zacznij programować w Pythonie! Idealne dla osób bez doświadczenia. Praktyczne zadania, projekty i wsparcie społeczności.
- ✓24 lekcje wideo + 80 ćwiczeń
- ✓Realne bazy z e-commerce
- ✓Społeczność i code-review
W automatyzacji warto zbudować zestaw prostych reguł jakości. Każda reguła zwraca True albo False, a na końcu możesz policzyć wynik jakości.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25def quality_check(text: str | None) -> dict: """Sprawdza jakość tekstu według prostych reguł.""" text = text or "" checks = { "ma_min_3_znaki": len(text.strip()) >= 3, "brak_podwojnych_spacji": " " not in text, "nie_zaczyna_sie_od_interpunkcji": not text.strip().startswith(("!", "?", ".", ",")), "nie_jest_wylacznie_wielkimi": not text.strip().isupper(), "ma_tylko_drukowalne_znaki": all( char.isprintable() or char.isspace() for char in text ) } checks["score"] = round( sum(checks.values()) / len(checks), 2 ) return checks result = quality_check("Przykładowy tekst do sprawdzenia") print(result)
Taki wynik możesz zapisać w raporcie jakości danych albo użyć do odrzucenia rekordów, które wymagają ręcznej weryfikacji.
Czyszczenie listy tekstów
W praktyce często czyścisz nie jeden tekst, ale całą listę wartości. Poniżej przykład funkcji, która czyści listę, usuwa puste wartości i duplikaty.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31def clean_text_list(texts: list[str]) -> list[str]: """Czyści listę tekstów, usuwa puste wartości i duplikaty.""" cleaned = [] seen = set() for text in texts: value = normalize_polish_text(text) if not value: continue key = value.lower() if key in seen: continue seen.add(key) cleaned.append(value) return cleaned texts = [ " Jan Kowalski ", "Jan Kowalski", "", "Anna Nowak", "anna nowak" ] print(clean_text_list(texts))
To przydatne przy czyszczeniu nazw klientów, kategorii, tagów, miast lub wartości z formularzy.
Czyszczenie kolumn tekstowych w pandas
Jeśli pracujesz z danymi tabelarycznymi, najlepiej połączyć walidację tekstu z pandas.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27import pandas as pd def clean_text_columns(df: pd.DataFrame) -> pd.DataFrame: """Czyści wszystkie kolumny tekstowe w DataFrame.""" df = df.copy() text_columns = df.select_dtypes(include=["object"]).columns for column in text_columns: df[column] = ( df[column] .fillna("") .astype(str) .map(normalize_polish_text) ) return df df = pd.DataFrame({ "imie": [" Jan ", "Anna", None], "email": [" jan@example.com ", "anna.example.com", ""], "miasto": [" Warszawa", "Kraków ", " "] }) clean_df = clean_text_columns(df) print(clean_df)
Takie czyszczenie warto wykonać przed walidacją, eksportem do Excela, zapisem do bazy danych albo wysłaniem danych przez API.
Raport walidacji danych tekstowych
Możesz przygotować prosty raport, który pokaże, które rekordy mają błędny e-mail, pustą nazwę albo zły numer telefonu.
Python1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29import pandas as pd def validate_contacts(df: pd.DataFrame) -> pd.DataFrame: """Tworzy raport walidacji kontaktów.""" df = clean_text_columns(df) report = df.copy() report["email_poprawny"] = report["email"].apply(validate_email) report["telefon_poprawny"] = report["telefon"].apply(validate_polish_phone) report["nazwa_poprawna"] = report["nazwa"].str.len() >= 3 report["czy_poprawny_rekord"] = ( report["email_poprawny"] & report["telefon_poprawny"] & report["nazwa_poprawna"] ) return report contacts = pd.DataFrame({ "nazwa": ["Jan Kowalski", "A", "Anna Nowak"], "email": ["jan@example.com", "zly-email", "anna@example.com"], "telefon": ["+48 123 456 789", "123", "500600700"] }) validation_report = validate_contacts(contacts) print(validation_report)
Taki raport można zapisać do Excela i przekazać do poprawy osobie odpowiedzialnej za dane.
Dobre praktyki walidacji i czyszczenia tekstu
Przy pracy z tekstem warto trzymać się kilku zasad:
- czyść dane przed walidacją,
- nie usuwaj polskich znaków, jeśli są potrzebne biznesowo,
- waliduj formaty przez regex tylko tam, gdzie ma to sens,
- dla NIP i podobnych numerów sprawdzaj sumę kontrolną,
- zapisuj błędne rekordy do raportu,
- nie poprawiaj automatycznie danych, jeśli nie masz pewności,
- normalizuj białe znaki i twarde spacje,
- testuj reguły na prawdziwych danych,
- oddziel funkcje czyszczące od funkcji walidujących,
- loguj liczbę poprawionych i odrzuconych rekordów.
Najważniejsze: walidacja nie powinna ukrywać problemów. Jej zadaniem jest wykrywać błędy i pomagać je bezpiecznie obsłużyć.
Podsumowanie
Walidacja i czyszczenie tekstu w Pythonie pomagają utrzymać jakość danych w automatyzacji. Podstawowe techniki to normalizacja białych znaków, czyszczenie znaków specjalnych, walidacja regex, sprawdzanie sum kontrolnych, normalizacja Unicode i wykrywanie anomalii.
Najlepszy workflow wygląda tak: najpierw oczyść tekst, potem sprawdź formaty, następnie wykryj anomalie i zapisz błędne rekordy do raportu. Dzięki temu dalsze etapy — raportowanie, import do bazy, integracje API albo analiza danych — są stabilniejsze.
Jeśli chcesz zacząć praktycznie, przygotuj zestaw funkcji do walidacji e-maila, telefonu i NIP-u, a potem użyj ich na danych z Excela lub CSV. To prosty fundament pod automatyczną kontrolę jakości danych tekstowych.
➡️ Następny artykuł
Po opanowaniu walidacji danych naucz się generować profesjonalne raporty:
Raporty z Pandas do PDF/CSV/Excel — tworzenie profesjonalnych raportów z DataFrame'ów w różnych formatach, z formatowaniem i wykresami.



