Coverage for presidio_analyzer / predefined_recognizers / generic / mac_recognizer.py: 94%
17 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
1import re
2from typing import List, Optional
4from presidio_analyzer import Pattern, PatternRecognizer
7class MacAddressRecognizer(PatternRecognizer):
8 """
9 Recognize MAC (Media Access Control) address using regex.
11 Supports three common MAC address formats:
12 - Colon-separated: 00:1A:2B:3C:4D:5E
13 - Hyphen-separated: 00-1A-2B-3C-4D-5E
14 - Cisco format (dot-separated groups of 4): 0012.3456.789A
16 ref :
17 - https://en.wikipedia.org/wiki/MAC_address#Notational_conventions
18 - https://www.ieee802.org/1/files/public/docs2020/yangsters-smansfield-mac-address-format-0420-v01.pdf
19 """
21 PATTERNS = [
22 Pattern(
23 "MAC_COLON_OR_HYPHEN",
24 r"\b[0-9A-Fa-f]{2}([:-])(?:[0-9A-Fa-f]{2}\1){4}[0-9A-Fa-f]{2}\b",
25 0.6,
26 ),
27 Pattern(
28 "MAC_CISCO_DOT",
29 r"\b[0-9A-Fa-f]{4}\.[0-9A-Fa-f]{4}\.[0-9A-Fa-f]{4}\b",
30 0.6,
31 ),
32 ]
34 CONTEXT = ["mac", "mac address", "hardware address", "physical address", "ethernet"]
36 def __init__(
37 self,
38 patterns: Optional[List[Pattern]] = None,
39 context: Optional[List[str]] = None,
40 supported_language: str = "en",
41 supported_entity: str = "MAC_ADDRESS",
42 name: Optional[str] = None,
43 ):
44 patterns = patterns if patterns else self.PATTERNS
45 context = context if context else self.CONTEXT
46 super().__init__(
47 supported_entity=supported_entity,
48 patterns=patterns,
49 context=context,
50 supported_language=supported_language,
51 name=name
52 )
54 def invalidate_result(self, pattern_text: str) -> bool:
55 """
56 Check if the pattern text is a valid MAC address format.
58 :param pattern_text: Text detected as pattern by regex
59 :return: True if invalidated (invalid MAC address)
60 """
61 # Remove separators and validate hex characters and length
62 cleaned = re.sub(r'[:\-.]', '', pattern_text)
64 # All characters must be valid hex
65 if re.fullmatch(r"[0-9A-Fa-f]{12}", cleaned) is None:
66 return True
68 # Optionally reject broadcast/multicast addresses if needed
69 # Broadcast: FF:FF:FF:FF:FF:FF
70 if cleaned.upper() == 'FFFFFFFFFFFF' or cleaned.upper() == '000000000000':
71 return True
73 return False