Bassie
Bassie

Reputation: 10400

Convert plain string to MAC Address format

I am trying to convert some string input into the correct format for working with a MAC address.

So I need to convert

00A0C914C829

to

00:A0:C9:14:C8:29

I have this PowerShell script to achieve this:

$string = "00A0C914C829"
$out = $string -replace "([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])", '$1$2:$3$4:$5$6:$7$8:$9$10:$11$12'
$out

Which outputs:

00:A0:C9:14:C8:29

But that regex seems ridiculously long.

Is there some way of making this more concise?


I think the problem is that I don't understand how groups work properly ... Would really appreciate if someone could point me in the right direction!

Upvotes: 3

Views: 8242

Answers (2)

user242114
user242114

Reputation: 59

To add to Joey's answer. .NET has the PhysicalAddress class with build in validation. The parse method accepts multiple formats

https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.physicaladdress.parse?view=net-5.0#System_Net_NetworkInformation_PhysicalAddress_Parse_System_String_

001122334455

00-11-22-33-44-55

0011.2233.4455 (.NET 5 and later versions only)

00:11:22:33:44:55 (.NET 5 and later versions only)

F0-E1-D2-C3-B4-A5

f0-e1-d2-c3-b4-a5 (.NET 5 and later versions only)

You would need to install PS7 to parse some of those. I needed it to parse the Cisco IOS format

Upvotes: 0

Joey
Joey

Reputation: 354794

Think about it in terms of smaller units. You actually want to insert : after every two characters (except at the end of the string) instead of trying to capture every single character and forcing it into the desired format.

$s -replace '..(?!$)', '$&:'

This regex matches two characters at a time and replaces them by the same characters ($& in a replacement string represents the match) followed by :. Except at the end of the string, which is done via a negative lookahead preventing a match at the end of the string. This works because the regex engine won't look for matches that extend backwards into previous matches. So after the first two characters have been matched, the next match can only occur after that first one. This implicitly gives you groups of two characters to replace.

Instead of . you can also use [0-9a-f] if you really want, but I think input validation is a different problem than output formatting here. The output code should be able to trust that the string indeed contains only hexadecimal digits.

Validation can be done as simply as

if ($s -notmatch '^[0-9a-f]{12}$') {
  throw
}

And it's actually easier to detect a malformed string this way than by detecting whether the replacement did nothing.

Upvotes: 10

Related Questions