Dienstag, 4 November 2025

Top 5 diese Woche

Ähnliche Tutorials

Personalausweise

Unser Python Script liest eine Maschinenlesbare Zone MRZ im TD1 Format ein, parst die relevanten Felder und validiert Prüfziffern nach dem ICAO Standard 9303. Es dient als defensives und edukatives Werkzeug zur Plausibilitätsprüfung von Ausweisdaten. Ziel ist es, offensichtliche Formatfehler, fehlerhafte Prüfziffern und grobe Inkonsistenzen zu erkennen, nicht eine vollständige oder rechtlich bindende Identitätsprüfung zu ersetzen.

Einsatzbereich und Grenzen
Das Script ist für Vorprüfungen im Rahmen von Entwicklungsprojekten, Tests und Bildungszwecken gedacht. Es ersetzt keine vollständige Identitätsprüfung. Für produktive Anwendungen sind zusätzliche Schritte notwendig, etwa die visuelle Abgleichung mit dem Ausweisfoto, die Prüfung elektronischer Signaturen auf dem Chip, und die Nutzung offizieller Bibliotheken und SDKs. Das Script behandelt nur die Zeichenkodierung und Prüfziffern der MRZ. Es führt keine optische Zeichenerkennung OCR durch, und es überprüft keine kryptografischen Signaturen.

Beim Einsatz in produktiven Systemen sind Datenschutz und rechtliche Vorgaben strikt zu beachten. MRZ Daten sind sensible personenbezogene Informationen. Speichere und übermittle diese Daten nur verschlüsselt, und implementiere Zugriffskontrollen. Nutze das Script niemals ohne ausdrückliche Einwilligung der betroffenen Person oder ohne rechtliche Grundlage.

import re
from typing import Dict, Tuple
_WEIGHTS = [7, 3, 1]
def _char_value(ch: str) -> int:
    if ch == '<':
        return 0
    if '0' <= ch <= '9':
        return ord(ch) - ord('0')
    if 'A' <= ch <= 'Z':
        return ord(ch) - ord('A') + 10
    raise ValueError(f"Ungültiges MRZ Zeichen: {ch!r}")
def compute_check_digit(field: str) -> str:
    total = 0
    for i, ch in enumerate(field):
        val = _char_value(ch)
        weight = _WEIGHTS[i % 3]
        total += val * weight
    return str(total % 10)
def verify_field_with_check(field: str, check_digit: str) -> bool:
    try:
        return compute_check_digit(field) == check_digit
    except ValueError:
        return False
def parse_td1_mrz(lines: Tuple[str, str, str]) -> Dict:
    l1, l2, l3 = lines
    if not (len(l1) == len(l2) == len(l3) == 30):
        raise ValueError("Erwartet werden drei MRZ Zeilen mit je 30 Zeichen")
    result = {}
    result["document_type"] = l1[0]
    result["issuing_state"] = l1[2:5]
    names_raw = l2[5:30]
    names = names_raw.split("<<", 1)
    surname = names[0].replace('<', ' ').strip()
    given_names = names[1].replace('<', ' ').strip() if len(names) > 1 else ""
    result["surname"] = surname
    result["given_names"] = given_names
    doc_number_field = l3[0:9]
    doc_number_check = l3[9]
    nationality = l3[10:13]
    dob_field = l3[13:19]
    dob_check = l3[19]
    sex = l3[20]
    expiry_field = l3[21:27]
    expiry_check = l3[27]
    personal_number = l3[28:30]  # hier in TD1 meist kürzer, oft mit Füllzeichen
    result.update({
        "document_number": doc_number_field.replace('<', '').strip(),
        "document_number_check_valid": verify_field_with_check(doc_number_field, doc_number_check),
        "nationality": nationality,
        "date_of_birth_raw": dob_field,
        "date_of_birth_check_valid": verify_field_with_check(dob_field, dob_check),
        "sex": sex,
        "expiry_date_raw": expiry_field,
        "expiry_date_check_valid": verify_field_with_check(expiry_field, expiry_check),
        "personal_number_raw": personal_number
    })
    composite = doc_number_field + dob_field + expiry_field + personal_number
    composite_check = l3[30-1] if len(l3) >= 30 else None  # meist letzter Prüfwert vorhanden
    if composite_check:
        result["composite_check_valid"] = verify_field_with_check(composite, composite_check)
    return result
if __name__ == "__main__":
    mrz_example = (
        "IDDEUT<<<<<<<<<<<<<<<<<<<<<<<<<<<",
        "MUSTERMANN<<ERIKA<<<<<<<<<<<<<<<",
        "L01X00T12DEU8001015F2501012<<<<<<<<"
    )
    try:
        parsed = parse_td1_mrz(mrz_example)
        for k, v in parsed.items():
            print(f"{k}: {v}")
    except ValueError as e:
        print("Fehler beim Parsen der MRZ:", e)

Lesetipps für dich