Search code examples
pythonregexmac-addressregular-language

Regular expression (Python) - match MAC address


I have this text (from ipconfig /all)

Ethernet adapter Local Area Connection:

   Connection-specific DNS Suffix  . :    
   Description . . . . . . . . . . . : Atheros AR8151 PCI-E Gigabit Ethernet    Controller (NDIS 6.20)   
   Physical Address. . . . . . . . . : 50-E5-49-CE-FC-EF   
   DHCP Enabled. . . . . . . . . . . : Yes   
   Autoconfiguration Enabled . . . . : Yes    
   Link-local IPv6 Address . . . . . : fe80::5cba:e9f2:a99f:4499%11(Preferred)    
   IPv4 Address. . . . . . . . . . . : 10.0.0.1(Preferred)    
   Subnet Mask . . . . . . . . . . . : 255.255.255.0   
   Lease Obtained. . . . . . . . . . : ™ 06 €…‚…‘ˆ 2016 20:35:49   
   Lease Expires . . . . . . . . . . : ‰…™‰™‰ 09 €…‚…‘ˆ 2016 21:05:49   
   Default Gateway . . . . . . . . . : 10.0.0.138   
   DHCP Server . . . . . . . . . . . : 10.0.0.138   
   DHCPv6 IAID . . . . . . . . . . . : 240182601   
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-19-7A-1F-FC-50-E5-49-CE-FC-EF   
   DNS Servers . . . . . . . . . . . : 10.0.0.138   
   NetBIOS over Tcpip. . . . . . . . : Enabled    

Ethernet adapter Local Area Connection* 11:   

   Description . . . . . . . . . . . : Juniper Networks Virtual Adapter    
   Physical Address. . . . . . . . . : 02-05-85-7F-EB-80     
   DHCP Enabled. . . . . . . . . . . : No    
   Autoconfiguration Enabled . . . . : Yes    
   Link-local IPv6 Address . . . . . : fe80::8dfb:6d42:97e1:2dc7%19(Preferred)     
   IPv4 Address. . . . . . . . . . . : 172.16.2.7(Preferred)      
   Subnet Mask . . . . . . . . . . . : 255.255.255.255     
   Default Gateway . . . . . . . . . :       
   DHCPv6 IAID . . . . . . . . . . . : 436340101     
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-19-7A-1F-FC-50-E5-49-CE-FC-EF    
   DNS Servers . . . . . . . . . . . : 172.16.0.6     
                                       172.16.0.91     
   NetBIOS over Tcpip. . . . . . . . : Enabled     

I want to mach only the Physical Address (MAC)

From here it's will be 2:
50-E5-49-CE-FC-EF and 02-05-85-7F-EB-80

This (link) ([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) will not work because
This will mach also 00-01-00-01-19-7A-1F-FC-50-E5-49-CE-FC-EF
So I've fixed it to this ([^-])([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})([^-]) (force not - in the start and in the end)
But now I get in the mach the whitespace in the begining and in the end I get /n.
Here is the link: https://regex101.com/r/kJ7mC0/1

I need an elegant regex to solve it.


Solution

  • You get the non-- symbols on both sides because the negated character class [^-] matches and consumes the characters. To avoid getting these characters in the match value, you can use lookarounds:

    p = re.compile(r'(?<!-)(?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}(?!-)', re.IGNORECASE)
                     ^^^^^^                                  ^^^^
    

    The (?<!-) negative lookbehind makes sure there is no - before the value you need to extract, and (?!-) is a negative lookahead that fails the match if there is a - after this value.

    If the : delimiter is not expected, replace [:-] with -. Use it with re.findall.

    Also, all the (...) should be turned to (?:...) non-capturing groups so as not to "spoil" the match results.

    See the Python demo

    An alternative can be a regex with 1 capturing group capturing what we need, and matching what we do not need:

    p = re.compile(r'(?:^|[^-])((?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2})(?:$|[^-])', re.IGNORECASE)
    

    It does not look that elegant, but will work the same way as (?:^|[^-]) non-capturing group is not included in the re.findall results, and matches either the start of string or a symbol other than -. (?:$|[^-]) matches the end of string or a symbol other than -.

    Also, to shorten the pattern, you may replace a-fA-F with just a-f in the character classes and use the re.IGNORECASE or re.I flag.