3

I'm reading in MAC addresses on my LAN using the arp -a command and parsing the output. On OS X, some MAC addresses are returned with hex values lacking leading zeros. I've figured out how to insert the leading zeros using regex:

>>> mac = '8:AA:C:3:ED:E'
>>> mac = re.sub('^(?P<hex>.)(?=\:)','0\g<hex>',mac)
>>> mac = re.sub('(?<=\:)(?P<hex>.)(?=\:)','0\g<hex>',mac)
>>> mac = re.sub('(?<=\:)(?P<hex>.)$','0\g<hex>',mac)
>>> print mac

08:AA:0C:03:ED:0E

This works, but I'm sure there's a way to perform a replacement in a single line for an arbitrary MAC address, where any hex value can potentially lack a leading zero...I just can't figure it out.

  • As much fun as trying to do this in one line is, we're mostly throwing readability to the wind... – Mike DeSimone May 18 '14 at 03:50
  • True. Though, some of these answers have definitely improved readability compared to my initial solution that relied on cryptic regex syntax. – PGROCKETMAN May 18 '14 at 04:07
  • BTW, as much as it may just be shouting at the ocean, there's something else to note in alecxe's answer: IEEE has been trying to get people to use dashes instead of colons for the separators in MAC addresses, in order to prevent confusion with IPv6 addresses. – Mike DeSimone May 18 '14 at 15:13

4 Answers4

8

One option is not to reinvent the wheel and use netaddr module:

>>> from netaddr import EUI
>>> mac = '8:AA:C:3:ED:E'
>>> mac = EUI(mac)
>>> mac
EUI('08-AA-0C-03-ED-0E')
>>> str(mac)
'08-AA-0C-03-ED-0E'

As a bonus, you would get a nice standardized API.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • Is there a standard library solution with a similarly convenient interface? – user2357112 May 18 '14 at 03:28
  • @user2357112 mm, not that I'm aware of. – alecxe May 18 '14 at 03:30
  • @user2357112 What's wrong with a third party library? – SethMMorton May 18 '14 at 03:33
  • @SethMMorton: [Dependency hell](http://en.wikipedia.org/wiki/Dependency_hell), for one thing. – user2357112 May 18 '14 at 03:36
  • @user2357112 If this is the only thing you want to do with the mac address, just create a function. – Scorpion_God May 18 '14 at 03:38
  • Maybe back in 2001, but since this package is on PyPI, it can be automatically installed if you use pip. I have been using python for years now, and have *never* experienced dependency hell when installing a python library because I use pip. – SethMMorton May 18 '14 at 03:38
  • 1
    Guys, it's a never-ending argument. My boss would kill me for this approach, but I would do it anyway :) Some people just have a special thing with dependencies :) – alecxe May 18 '14 at 03:40
  • 2
    @alecxe: Where I work, the special thing is called "contractual requirements", namely "software must run on a stock RHEL 6 (or whatever) box with no additional packages installed, and no you're not allowed to install your own as part of the delivery, and no virtualenv either." I.e. no fun. – Mike DeSimone May 18 '14 at 03:47
5
>>> mac = '8:AA:C:3:ED:E'
>>> print ':'.join([i.zfill(2) for i in mac.split(':')])
08:AA:0C:03:ED:0E

To use it like a "standard library" with a "convenient interface":

>>> def fix_mac_adr(adr):
        return ':'.join([i.zfill(2) for i in adr.split(':')])
>>> fix_mac_adr('8:AA:C:3:ED:E')
'08:AA:0C:03:ED:0E'

One-liner (from Mike DeSimone):

>>> fix_mac_adr = lambda adr: ':'.join([i.zfill(2) for i in adr.split(':')])
Scorpion_God
  • 1,499
  • 10
  • 15
  • @alecxe Yes, you're right. More efficient as a generator. – Scorpion_God May 18 '14 at 03:32
  • Make the definition one line, too! `fix_mac_adr = lambda adr: ':'.join(str(i).zfill(2) for i in adr.split(':'))` – Mike DeSimone May 18 '14 at 03:49
  • 1
    If someone told you that `str.join`ing a generator expression is "more efficient" than joining a list comprehension, [they're wrong](http://stackoverflow.com/questions/9060653/list-comprehension-without-python/9061024#9061024) – roippi May 18 '14 at 04:19
  • 1
    Correcting myself: `str(i)` is redundant since the result of `str.split` is a list of strings. Therefore `fix_mac_adr = lambda a: ':'.join([i.zfill(2) for i in a.split(':')])` – Mike DeSimone May 18 '14 at 15:10
1

You can also do it using string formatting as follows:

mac = '8:AA:C:3:ED:E'

>>> print ':'.join('{:0>2}'.format(i) for i in mac.split(':'))
08:AA:0C:03:ED:0E
sshashank124
  • 31,495
  • 9
  • 67
  • 76
0
mac = '8:AA:C:3:ED:E'
":".join(("0" if len(part)==1 else "")+part for part in mac.split(":"))

Output:

Out[45]: '08:AA:0C:03:ED:0E'
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241