How to Normalize MAC Addresses Into One Canonical Form
Three notations, two cases, one device. Learn why network inventories and allowlists break until you normalize MAC addresses to a single canonical form.
How to Normalize MAC Addresses Into One Canonical Form
A MAC address identifies one network interface, and it never changes. But the way people write it down does. The same 48-bit hardware address can show up three different ways in three different tools, and unless you reduce them all to one shape, your scripts will swear they are looking at three separate devices.
That mismatch is not a rare edge case. It is the default state of any inventory that pulls from more than one source. This post walks through the three notations, the casing problem layered on top of them, and how to flatten everything into one form you can actually match against.
Three ways to write the same address
Vendors disagree on punctuation. The IEEE writes MAC addresses with hyphens. Most Linux tooling and packet captures use colons. Cisco invented its own dotted-quad style to save horizontal space in switch tables. All three describe the identical interface:
- Colon-separated:
00:1A:2B:3C:4D:5E - Hyphen-separated:
00-1A-2B-3C-4D-5E - Cisco dotted:
001a.2b3c.4d5e
Look closely at that third form. Cisco groups the twelve hex digits into three blocks of four and joins them with dots, so the byte boundaries do not even line up with the human eye. A bare hex run like 001a2b3c4d5e is a fourth variant some exports produce when they strip punctuation entirely.
Now stack casing on top. Hex digits A through F can be upper or lower case, and nothing forces consistency. 00:1A:2B:3C:4D:5E and 00:1a:2b:3c:4d:5e are the same address to a network card and two different strings to a grep.
Why the mismatch silently breaks inventories
Here is the concrete failure. Your access switch dumps its forwarding table in Cisco dotted form: 001a.2b3c.4d5e. Your DHCP server logs the same lease in lower-case colon form: 00:1a:2b:3c:4d:5e. Your security team maintains an allowlist in upper-case hyphen form: 00-1A-2B-3C-4D-5E.
Three records. One physical device. Zero string matches between them.
When you JOIN the switch table against the DHCP log on the MAC column, the row count comes back empty and you assume the device is offline. When you check the allowlist for that interface, it is "not found," so a known-good laptop trips an alert. None of this is a logic bug. It is a formatting bug, and it stays invisible until someone normalizes the columns to one notation and one case.
That is the entire job: pick a canonical form, rewrite every variant into it, and only then compare. The MAC Address Normalizer rewrites Cisco dotted form, hyphen form, and bare hex into a single colon-separated, single-case style so the switch table, the DHCP log, and the allowlist finally line up on the same string.
A worked example
Suppose you paste a messy list scraped from three systems into the tool:
001A.2B3C.4D5E
00-1a-2b-3c-4d-5e
00:1A:2B:3C:4D:5E
AABB.CCDD.EEFF
The first three lines are the same device written in Cisco dotted, hyphen, and colon notation with mixed casing. The fourth is a different interface in Cisco form. After normalizing to colon-separated lower case and keeping unique rows only, the output collapses to two entries:
00:1a:2b:3c:4d:5e
aa:bb:cc:dd:ee:ff
The three representations of the first address deduplicate into one row, because once they share a canonical string they are finally recognized as identical. That is the payoff: dedupe and matching only work after normalization, never before.
Choosing one output format
A clean list is the start, but the next system rarely wants raw lines. The normalizer can emit the result as plain lines, CSV, JSON, Markdown, a SQL IN clause, or a TypeScript union, so the canonical addresses drop straight into the place you actually need them.
If you are filtering a database, the SQL IN form gives you a ready clause instead of hand-quoting each value. If you are seeding a fixture or a config file, JSON or the TypeScript union saves you from chasing missing commas. CSV with line numbers is the one I reach for when an audit trail matters, because it preserves which source line each address came from.
How I use it in practice
I keep a recurring chore of reconciling a switch forwarding table against an allowlist spreadsheet, and for a long time I did the casing fix by hand with find-and-replace, which is exactly as error-prone as it sounds. The first time I dropped both lists into the normalizer set to colon-lower-case and turned on dedupe, the reconciliation that used to take twenty minutes of squinting collapsed into a single paste. What surprised me was a duplicate I had been carrying for months: two "different" entries in my allowlist were the same interface, one in Cisco dotted form and one in colon form, and they had never collided because the strings never matched until I normalized them. The dedupe pass caught it instantly.
Keep the invalid rows honest
Normalization should never guess. A five-group string like 00:1A:2B:3C:4D has only ten hex digits where a MAC needs twelve, so there is no honest way to rewrite it. Rather than fabricate a missing byte, the tool leaves that row untouched and flags the reason, so the normalized column stays trustworthy. You can keep invalid rows in the output for review or filter them out, but you are never handed a silently invented address.
One more caution worth repeating: a well-formed MAC is not proof the device exists or is authorized. Normalization fixes the string, not the fact. Pair it with your real source of truth before you act on the list.
If your raw data needs splitting before it ever reaches normalization, pull the addresses out first and then run the cleaned set through here. Extract, normalize, dedupe, export. Four steps, one canonical form, and an inventory that finally agrees with itself.
Made by Toolora · Updated 2026-06-13