Search code examples
javascripthextyped-arrays

Converting an Array of Hexadecimal Strings to Numbers


I have an application in which a server is sending a lot of data every second to clients that request it. In this data set are several (large) arrays that contain numbers (in some cases 16-bit integers and in others double precision floats). In order to reduce the packet size, I would like to send only the number of bytes that are necessary to represent the number (2 bytes for the 16 bit and 8 for the 64 bit). I know that I can do something like this:

/* Create space for 4 32 bit numbers */
var buffer = new ArrayBuffer(16);

/* Hex representation of [0, 123, 246, 369] */
buffer = ["0x0", 0x7B", "0xF6", "0x171"];

/* Actual array containing numbers above */
var int32View = new Int32Array(buffer); 

but....I don't want to prepend everything sting with "0x" (adding two bytes will double the size of the 16 bit numbers). I think I might be missing something - is there a better way to do this such that I don't need to indicate that the strings are hexadecimal representations of numbers (i.e. can I drop the "0x")?

Thanks, Matt


Solution

  • You can use map() or a for-loop to treat each value and use the length as basis for where to sort them out.

    One note though, you mention 64-bit floats. When these are extracted from a buffer they will be 64-bit integer values (ie. 0xXXXXXXXXXXXXXXXX) formatted in IEEE-754 format.

    However, JavaScript can only work with 32-bit values (0xXXXXXXXX) so you have to split the processing of those into two parts using a 32-bit unsigned array, then add a Float64Array view for that later.

    If the float values are literals, ie "2.345", "-1.33" etc. then you can simply use parseFloat(str) on them (instead of handling 64-bit values as below).

    Example

    // inserted 64-bit IEEE float of -2.3357 = 0x7b4a233ac002af83
    var normArray = ["0", "7B", "F6", "7b4a233ac002af83", "171"],
        int16a = [], int32a = [],
        int16b, int32b, float64b;
    
    normArray.map(function(entry) {
      if (entry.length > 4) {
        var high = entry.substr(0, 8),
            low = entry.substr(8, 8);
        int32a.push(parseInt(high, 16), parseInt(low, 16));
      }
      else {
        int16a.push(parseInt(entry, 16));
      }
    });
    
    // convert to typed arrays
    int16b = new Int16Array(int16a);
    int32b = new Uint32Array(int32a);
    float64b = new Float64Array(int32b.buffer); // convert IEEE rep. to floats
    
    document.writeln("<pre>int16  : " +
                    int16b[0] + ", " + int16b[1] + ", " + int16b[2] + ", ...");
    document.write("float64: " + float64b[0] + "</pre>")