9

I have a MAC address stored as a raw 48 bit number, and I want to split it up and print it in the standard hex format of xx:xx:xx:xx:xx:xx. For example, the raw number 81952921372024 should become 78:45:c4:26:89:4a. My first attempt was,

var suspect = {mac: 2333752735057272};
console.log(
    Number(suspect.mac & 0xFF).toString(16) + ":" +
    Number((suspect.mac & 0xFF00) >> 8).toString(16) + ":" +
    Number((suspect.mac & 0xFF0000) >> 16).toString(16) + ":" +
    Number((suspect.mac & 0xFF000000) >> 24).toString(16) + ":" +
    Number((suspect.mac & 0xFF00000000) >> 32).toString(16) + ":" +
    Number((suspect.mac & 0xFF0000000000) >> 48).toString(16));

But because Javascript apparently can't handle > 32 bit integers when doing shift operations, the last two octets always come out to 0,

78:45:c4:26:0:0 
ajp15243
  • 7,704
  • 1
  • 32
  • 38
PherricOxide
  • 15,493
  • 3
  • 28
  • 41
  • 2
    `2333752735057272..toString(16)` gives `84a8926c44578` to me in Chrome. What if you take that, crop the first digit, and reverse the octets? – bfavaretto Jul 29 '13 at 20:28
  • You sure that MAC address is right? It looks out of range to me. – user2357112 Jul 29 '13 at 20:28
  • 2
    Indeed, JavaScript has no concept of >32-bit integers, or even really of 32-bit integers; it just has a `number` type, meaning double-precision (64-bit) floating-point values, and various integer-y operations, such as bit-shifts, do an implicit conversion to and from 32-bit integers. – ruakh Jul 29 '13 at 20:29
  • I'm pretty sure you've got a 52-bit number there, and your byte order doesn't look right either. – user2357112 Jul 29 '13 at 20:35
  • Yeah, there was a bug earlier and the number wasn't quite right. Sorry about that, should have been 81952921372024. Editing now. – PherricOxide Jul 29 '13 at 20:45
  • The byte order is because it's in network byte order (big-endian). Can't really change that in the number I get, will have to flip everything around after it's converted. – PherricOxide Jul 29 '13 at 20:47
  • So, just `.toString(16)` on the original number and reverse the octets as I suggested initially. You were losing information because of the bitshift operations, as pointed out bu @ruakh. – bfavaretto Jul 29 '13 at 20:48

3 Answers3

20

A simple approach looks as follows:

var mac = 81952921372024;

mac.toString( 16 )             // "4a8926c44578"
        .match( /.{1,2}/g )    // ["4a", "89", "26", "c4", "45", "78"]
        .reverse()             // ["78", "45", "c4", "26", "89", "4a"]
        .join( ':' )           // "78:45:c4:26:89:4a"

> "78:45:c4:26:89:4a"

However I suggest putting additional 00 groups just for pathological cases when your integer is very short (i.e. mac = 150):

var mac = 81952921372024;

new Array( 6 ).join( '00' )    // '000000000000'
    .match( /../g )            // [ '00', '00', '00', '00', '00', '00' ]
    .concat( 
        mac.toString( 16 )     // "4a8926c44578"
           .match( /.{1,2}/g ) // ["4a", "89", "26", "c4", "45", "78"]
    )                          // ["00", "00", "00", "00", "00", "00", "4a", "89", "26", "c4", "45", "78"]
    .reverse()                 // ["78", "45", "c4", "26", "89", "4a", "00", "00", "00", "00", "00", "00", ]
    .slice( 0, 6 )             // ["78", "45", "c4", "26", "89", "4a" ]
    .join( ':' )               // "78:45:c4:26:89:4a"

> "78:45:c4:26:89:4a"
oleq
  • 15,697
  • 1
  • 38
  • 65
  • Why make an array filled with `0`? Wouldn't directly using the array produced by `match` on the stringified version of `mac` (`mac.toString(16).match(/../g).reverse().join(':')`) be easier, rather than concatenating it onto the longer array and having to do a substring? – ajp15243 Jul 29 '13 at 21:08
  • @ajp15243 Updated the answer with an explanation. – oleq Jul 29 '13 at 21:21
  • Unfortunately this did not work for me. The mac 1025 (00:00:00:00:04:01) was turned into 1:40:00:00:00:00, which is obviously not correct. – Dominik Mar 02 '17 at 02:34
  • 1
    For some reason, when I try the above in chrom console, the output string is always reversed. Eg, ```var mac = "159534546944"``` ( which is 00:25:25:00:00:00 according to [this online converter](https://www.vultr.com/tools/mac-converter/?mac_address=00%3A25%3A25%3A00%3A00%3A00). When I run it through the above code, I end up with ```"00:00:00:25:25:00"```. I need to always ```.split(":").reverse().join(":")``` to get the correct value. – blueren Dec 07 '18 at 07:09
  • This may not be relevant but on Scala the same can be achieved via `(Array.fill(6)("00") ++ new RichLong(macAddr).toHexString.split("(?<=\\G.{2})")).reverse.slice(0, 6).mkString(":")` – forevergenin Nov 01 '19 at 19:42
1

The following does the job,

var hexValue = parseInt('44873434449413').toString(16);

var macaddress = [];

for (var i=0; i < hexValue.length; i=i+2) {
    macaddress.push(hexValue.substr(i,2));    
}


console.log(macaddress.join(':'));

Output:
28:cf:e9:1e:c6:05

EDIT:

to take care of trailing 0's

str='3';
if (str.length < 12) { str = pad_after(str, 12, 0);}

var hexValue = parseInt(str).toString(16);

if (hexValue.length < 12) { hexValue = pad_before(hexValue, 12, 0);}

var macaddress = [];

for (var i=0; i < hexValue.length; i=i+2) {
    macaddress.push(hexValue.substr(i,2));    
}

console.log(macaddress.join(':'));


function pad_before(n, width, z) {
  z = z || '0';
  n = n + '';
  return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

function pad_after(n, width, z) {
  z = z || '0';
  n = n + '';
  return n.length >= width ? n : n + new Array(width - n.length + 1).join(z);
}

Output:
00:45:d9:64:b8:00

v2b
  • 1,436
  • 9
  • 15
  • Doesn't work if the octets are all zero on the ends. For example, hexValue = 3, it doesn't ever loop through and populate the macaddress array. – PherricOxide Jul 29 '13 at 21:19
1

The accepted answer did not pass my unit tests (convert mac address to a number then convert back and expect the result equals the input).

As @blueren said the accepted answer returns a reversed result.

My version is:

(mac_num).toString(16).padStart(12, '0').match(/../g)
                .reverse()
                .slice(0, 6)
                .reverse()
                .join(':')

My tests:

        expect(mac.toString(mac.toLong('b4:ae:2b:db:1c:3d'))).to.deep.equal('b4:ae:2b:db:1c:3d');
        expect(mac.toString(mac.toLong('00:00:00:db:1c:3d'))).to.deep.equal('00:00:00:db:1c:3d');
        expect(mac.toString(mac.toLong('b4:ae:2b:00:00:00'))).to.deep.equal('b4:ae:2b:00:00:00');
        expect(mac.toString(mac.toLong('00:00:00:00:00:00'))).to.deep.equal('00:00:00:00:00:00');
        expect(mac.toString(mac.toLong('10:00:00:00:00:00'))).to.deep.equal('10:00:00:00:00:00');
        expect(mac.toString(mac.toLong('00:00:01:00:00:00'))).to.deep.equal('00:00:01:00:00:00');
        expect(mac.toString(mac.toLong('00:00:00:00:00:01'))).to.deep.equal('00:00:00:00:00:01');
haolun
  • 304
  • 1
  • 9