Coverage for presidio_analyzer / predefined_recognizers / country_specific / germany / de_kfz_recognizer.py: 100%
9 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-29 09:03 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-29 09:03 +0000
1from typing import List, Optional
3from presidio_analyzer import Pattern, PatternRecognizer
6class DeKfzRecognizer(PatternRecognizer):
7 """
8 Recognizes German vehicle registration plates (KFZ-Kennzeichen).
10 German license plates are issued by local Zulassungsbehörden (vehicle registration
11 authorities). While not exclusively personal (vehicles can be owned by companies),
12 they can be linked to natural persons and are considered personally identifiable
13 information in the context of data protection law.
15 Legal basis: Fahrzeug-Zulassungsverordnung (FZV) § 8, § 9.
16 Data protection: DSGVO Art. 4 Nr. 1 (personenbezogene Daten) – license plates
17 constitute personal data when they can be linked to an identifiable person (ECJ
18 ruling C-582/14, Breyer v. Germany).
20 Format:
21 [Unterscheidungszeichen] [Erkennungszeichen] [Ziffern] [Suffix]
23 Unterscheidungszeichen: 1–3 uppercase letters (district/city code)
24 Erkennungszeichen: 1–2 uppercase letters
25 Ziffern: 1–4 digits
26 Suffix (optional): E (electric vehicle) or H (Oldtimer/historic, ≥30 years)
28 Examples
29 B AB 1234 (Berlin)
30 M XY 999 (München)
31 HH AB 1234 (Hamburg)
32 KA EF 1H (Karlsruhe, historic)
33 MIL E 1234E (Miltenberg, electric)
34 S AB 12 (Stuttgart)
36 Note: Seasonal plates (Saison-Kennzeichen) also contain month ranges but are not
37 covered by this pattern.
39 :param patterns: List of patterns to be used by this recognizer
40 :param context: List of context words to increase confidence in detection
41 :param supported_language: Language this recognizer supports
42 :param supported_entity: The entity this recognizer can detect
43 """
45 PATTERNS = [
46 Pattern(
47 "KFZ-Kennzeichen (mit Leerzeichen)",
48 r"(?<![\w-])[A-ZÄÖÜ]{1,3}\s[A-Z]{1,2}\s\d{1,4}[EH]?(?!\w)",
49 0.3,
50 ),
51 Pattern(
52 "KFZ-Kennzeichen (mit Bindestrich)",
53 r"(?<![\w-])[A-ZÄÖÜ]{1,3}-[A-Z]{1,2}-\d{1,4}[EH]?(?!\w)",
54 0.3,
55 ),
56 Pattern(
57 "KFZ-Kennzeichen (Bindestrich + Leerzeichen)",
58 r"(?<![\w-])[A-ZÄÖÜ]{1,3}-[A-Z]{1,2}\s\d{1,4}[EH]?(?!\w)",
59 0.3,
60 ),
61 Pattern(
62 "KFZ-Kennzeichen (ASCII only, mit Leerzeichen)",
63 r"(?<![\w-])[A-Z]{1,3}\s[A-Z]{1,2}\s\d{1,4}[EH]?(?!\w)",
64 0.2,
65 ),
66 Pattern(
67 "KFZ-Kennzeichen (ASCII only, Bindestrich + Leerzeichen)",
68 r"(?<![\w-])[A-Z]{1,3}-[A-Z]{1,2}\s\d{1,4}[EH]?(?!\w)",
69 0.2,
70 ),
71 ]
73 CONTEXT = [
74 "kennzeichen",
75 "kfz-kennzeichen",
76 "kraftfahrzeugkennzeichen",
77 "nummernschild",
78 "fahrzeugkennzeichen",
79 "zulassung",
80 "kfz",
81 "fahrzeug",
82 "auto",
83 "pkw",
84 "lkw",
85 "fahrzeugschein",
86 "fahrzeugbrief",
87 "zulassungsbescheinigung",
88 "amtliches kennzeichen",
89 ]
91 def __init__(
92 self,
93 patterns: Optional[List[Pattern]] = None,
94 context: Optional[List[str]] = None,
95 supported_language: str = "de",
96 supported_entity: str = "DE_KFZ",
97 name: Optional[str] = None,
98 ):
99 patterns = patterns if patterns else self.PATTERNS
100 context = context if context else self.CONTEXT
101 super().__init__(
102 supported_entity=supported_entity,
103 patterns=patterns,
104 context=context,
105 supported_language=supported_language,
106 name=name,
107 )