Coverage for presidio_analyzer / predefined_recognizers / country_specific / germany / de_fuehrerschein_recognizer.py: 100%

9 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-03-29 09:03 +0000

1from typing import List, Optional 

2 

3from presidio_analyzer import Pattern, PatternRecognizer 

4 

5 

6class DeFuehrerscheinRecognizer(PatternRecognizer): 

7 r""" 

8 Recognizes German Führerscheinnummern (driving license numbers). 

9 

10 The Führerscheinnummer is the document number printed in Field 5 of the 

11 German driving license card. Since the EU-harmonized credit-card format 

12 was introduced on 19 January 2013 (EU Directive 2006/126/EC, implemented 

13 via FeV reform), the number follows a fixed 11-character structure: 

14 

15 Pos 1–2: Behördenkürzel – 2 uppercase letters identifying the issuing 

16 Fahrerlaubnisbehörde (derived from the Kfz-Zulassungskürzel of 

17 the issuing Kreis/Stadt, e.g. "B0" Berlin, "MU" München, 

18 "HH" Hamburg, "KO" Koblenz) 

19 Pos 3–5: Behördennummer – 3-digit authority code within the Bundesland 

20 (assigned by the Kraftfahrt-Bundesamt, KBA) 

21 Pos 6–10: Laufende Nummer – 5-digit sequential issue number 

22 Pos 11: Prüfzeichen – 1 check character (uppercase letter A–Z or 

23 digit 0–9); the derivation algorithm is not published by KBA 

24 

25 Legal basis: FeV Anlage 8 (Fahrerlaubnis-Verordnung, Anlage 8 – Muster des 

26 Führerscheins), KBA Schlüsselverzeichnis der Fahrerlaubnisbehörden. 

27 EU standard: Annex I to Directive 2006/126/EC (Field 5). 

28 Data protection: DSGVO Art. 4 Nr. 1 (personenbezogene Daten), BDSG. 

29 

30 Examples (fictitious): B012345678A, MU12345678B, HH98765432C 

31 

32 Scope note: Pre-2013 German driving licenses (pink folded card, laminated 

33 card) used locally defined, non-standardized number formats and remain 

34 legally valid until 2033 under EU grandfathering rules. Their numbers do 

35 not reliably fit the 11-character pattern and are therefore out of scope 

36 for this recognizer. Context words (e.g. "Führerschein", "Fahrerlaubnis") 

37 remain the primary means of distinguishing true license numbers from 

38 other 11-character alphanumeric codes. 

39 

40 No checksum validation is implemented because the Prüfzeichen derivation 

41 formula is not published in FeV Anlage 8 or KBA administrative documents. 

42 

43 Accuracy note: The pattern ``[A-Z]{2}\\d{8}[A-Z0-9]`` (11 characters) is 

44 fairly specific, but context words are required for high-confidence matches 

45 because no computable checksum is available. The base confidence is set to 

46 0.35. Formal accuracy evaluation has not been performed on a labelled dataset. 

47 

48 :param patterns: List of patterns to be used by this recognizer 

49 :param context: List of context words to increase confidence in detection 

50 :param supported_language: Language this recognizer supports 

51 :param supported_entity: The entity this recognizer can detect 

52 """ 

53 

54 PATTERNS = [ 

55 Pattern( 

56 "Führerscheinnummer (Post-2013 EU-Format, 11 Zeichen)", 

57 r"\b[A-Z]{2}\d{8}[A-Z0-9]\b", 

58 0.35, 

59 ), 

60 ] 

61 

62 CONTEXT = [ 

63 "führerscheinnummer", 

64 "führerschein", 

65 "fahrerlaubnis", 

66 "fahrerlaubnisnummer", 

67 "fahrerlaubnisklasse", 

68 "führerscheininhaber", 

69 "fev", 

70 "kba", 

71 "kraftfahrt-bundesamt", 

72 "driving licence", 

73 "driving license", 

74 "driver's license", 

75 "licence number", 

76 "license number", 

77 "dokument nr", 

78 "dokument-nr", 

79 "feld 5", 

80 ] 

81 

82 def __init__( 

83 self, 

84 patterns: Optional[List[Pattern]] = None, 

85 context: Optional[List[str]] = None, 

86 supported_language: str = "de", 

87 supported_entity: str = "DE_FUEHRERSCHEIN", 

88 name: Optional[str] = None, 

89 ): 

90 patterns = patterns if patterns else self.PATTERNS 

91 context = context if context else self.CONTEXT 

92 super().__init__( 

93 supported_entity=supported_entity, 

94 patterns=patterns, 

95 context=context, 

96 supported_language=supported_language, 

97 name=name, 

98 )