Streszczenie
  • Kiedy warto walidować i czyścić tekst?
  • Podstawowe czyszczenie tekstu w Pythonie
  • Normalizacja białych znaków
  • Walidacja tekstu przez regex
Walidacja i czyszczenie tekstu w Pythonie

Walidacja i czyszczenie tekstu w Pythonie

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 · 24 lekcje8h 14m
Kurs

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
699 zł
Zacznij kurs Pythona

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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import 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:

1 To 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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 import 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

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import 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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import 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

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import 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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def 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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import 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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import 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

Newsletter · co środę

Python co tydzień — newsletter dla programistów

Otrzymuj codzienne ćwiczenia, ciekawostki z ekosystemu Pythona i wskazówki do rozmów rekrutacyjnych.

2 312 czytelników · ⭐ 4,8

Anomalie tekstowe to wartości, które odstają od reszty danych. Mogą być puste, podejrzanie krótkie, bardzo długie albo zawierać nietypowe znaki.

Python
1 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 42 def 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ąć.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import 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 · 24 lekcje8h 14m
Kurs

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
699 zł
Rozpocznij naukę

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.

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 def 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.

Python
1 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 def 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.

Python
1 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 import 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.

Python
1 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 import 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.

Część 18 z 26

Tworzenie interfejsów graficznych w Pythonie - wprowadzenie do Tkinter

druga lekcja cyklu „Automatyzacja procesów z n8n — od danych do AI w jednym narzędziu"

Czytaj kolejny →