cheziHoyzer cheziHoyzer - 3 months ago 34
Python Question

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.

Answer

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.

Comments