Reputation: 10400
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?
()
, which is why it is so long. I also tried matching with ^([0-9A-Fa-f]){12}$
, but this gave the output 9$2:$3$4:$5$6:$7$8:$9$10:$11$12
(12 groups of 1 character each)^(([0-9A-Fa-f]){2}){6}$
(6 groups of 2 characters each) and then the replacement: $1:$2:$3:$4:$5:$6
, but this gave output 29:9:$3:$4:$5:$6
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
Reputation: 59
To add to Joey's answer. .NET has the PhysicalAddress
class with build in validation. The parse method accepts multiple formats
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
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