Pack and unpack bytes to strings












26












$begingroup$


I need to write a function that "packs" an array of bytes (integers between 0 and 255) into a string. I also need to be able to perform the reverse operation, to get my byte array from the string that it was packed into. This needs to be done as fast as possible. Seeing as JavaScript has 16-bit strings, I packed two bytes per character. Here is my code and tests:



function pack(bytes) {
var str = "";
for(var i = 0; i < bytes.length; i += 2) {
var char = bytes[i] << 8;
if (bytes[i + 1])
char |= bytes[i + 1];
str += String.fromCharCode(char);
}
return str;
}

function unpack(str) {
var bytes = ;
for(var i = 0; i < str.length; i++) {
var char = str.charCodeAt(i);
bytes.push(char >>> 8);
bytes.push(char & 0xFF);
}
return bytes;
}

var tests = [
,
[126, 0],
[0, 65],
[12, 34, 56],
[0, 50, 100, 150, 200, 250]
];

console.log("starting tests");
tests.forEach(function(v) {
var p = pack(v);
console.log(v, p, unpack(p));
});


And the output to that is:



starting tests
""
[126, 0] "縀" [126, 0]
[0, 65] "A" [0, 65]
[12, 34, 56] "ఢ㠀" [12, 34, 56, 0]
[0, 50, 100, 150, 200, 250] "2撖죺" [0, 50, 100, 150, 200, 250]


So I have a few things I'd like feedback on.




  1. This was the first time I used bitwise operators. Is this how it should be done?

  2. Are there any speed improvements that could be made?

  3. Can you guys think of any way to discard that last 0 byte when encoding then decoding an array with an odd number of bytes? (see test #4)


Thanks.










share|improve this question









$endgroup$








  • 1




    $begingroup$
    Regarding 3., just add a sentinel to the end of your packed array indicating whether the final byte should be included or not.
    $endgroup$
    – Rafe
    Jul 21 '11 at 5:17










  • $begingroup$
    Good idea. I was gonna have 2 bytes at the beggining indicating length, but that would have limited the length to 65535. Using your method I can have more. Not that I need it, but it's always nice to break barriers.
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:04










  • $begingroup$
    Why on earth would you want to encode bytes on the client side? Seems like it should be something to do on the server.
    $endgroup$
    – Neil
    Jul 21 '11 at 13:14






  • 2




    $begingroup$
    Who said that was client side?
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:52












  • $begingroup$
    I have used this code and there seems to be a problem when passing 0 values to it, they get converted to '' omitted, making it unreliable to pack 32bit floats to a 4 chars. Is there any solution?
    $endgroup$
    – RenegadeMaster88
    Oct 16 '12 at 15:21
















26












$begingroup$


I need to write a function that "packs" an array of bytes (integers between 0 and 255) into a string. I also need to be able to perform the reverse operation, to get my byte array from the string that it was packed into. This needs to be done as fast as possible. Seeing as JavaScript has 16-bit strings, I packed two bytes per character. Here is my code and tests:



function pack(bytes) {
var str = "";
for(var i = 0; i < bytes.length; i += 2) {
var char = bytes[i] << 8;
if (bytes[i + 1])
char |= bytes[i + 1];
str += String.fromCharCode(char);
}
return str;
}

function unpack(str) {
var bytes = ;
for(var i = 0; i < str.length; i++) {
var char = str.charCodeAt(i);
bytes.push(char >>> 8);
bytes.push(char & 0xFF);
}
return bytes;
}

var tests = [
,
[126, 0],
[0, 65],
[12, 34, 56],
[0, 50, 100, 150, 200, 250]
];

console.log("starting tests");
tests.forEach(function(v) {
var p = pack(v);
console.log(v, p, unpack(p));
});


And the output to that is:



starting tests
""
[126, 0] "縀" [126, 0]
[0, 65] "A" [0, 65]
[12, 34, 56] "ఢ㠀" [12, 34, 56, 0]
[0, 50, 100, 150, 200, 250] "2撖죺" [0, 50, 100, 150, 200, 250]


So I have a few things I'd like feedback on.




  1. This was the first time I used bitwise operators. Is this how it should be done?

  2. Are there any speed improvements that could be made?

  3. Can you guys think of any way to discard that last 0 byte when encoding then decoding an array with an odd number of bytes? (see test #4)


Thanks.










share|improve this question









$endgroup$








  • 1




    $begingroup$
    Regarding 3., just add a sentinel to the end of your packed array indicating whether the final byte should be included or not.
    $endgroup$
    – Rafe
    Jul 21 '11 at 5:17










  • $begingroup$
    Good idea. I was gonna have 2 bytes at the beggining indicating length, but that would have limited the length to 65535. Using your method I can have more. Not that I need it, but it's always nice to break barriers.
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:04










  • $begingroup$
    Why on earth would you want to encode bytes on the client side? Seems like it should be something to do on the server.
    $endgroup$
    – Neil
    Jul 21 '11 at 13:14






  • 2




    $begingroup$
    Who said that was client side?
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:52












  • $begingroup$
    I have used this code and there seems to be a problem when passing 0 values to it, they get converted to '' omitted, making it unreliable to pack 32bit floats to a 4 chars. Is there any solution?
    $endgroup$
    – RenegadeMaster88
    Oct 16 '12 at 15:21














26












26








26


8



$begingroup$


I need to write a function that "packs" an array of bytes (integers between 0 and 255) into a string. I also need to be able to perform the reverse operation, to get my byte array from the string that it was packed into. This needs to be done as fast as possible. Seeing as JavaScript has 16-bit strings, I packed two bytes per character. Here is my code and tests:



function pack(bytes) {
var str = "";
for(var i = 0; i < bytes.length; i += 2) {
var char = bytes[i] << 8;
if (bytes[i + 1])
char |= bytes[i + 1];
str += String.fromCharCode(char);
}
return str;
}

function unpack(str) {
var bytes = ;
for(var i = 0; i < str.length; i++) {
var char = str.charCodeAt(i);
bytes.push(char >>> 8);
bytes.push(char & 0xFF);
}
return bytes;
}

var tests = [
,
[126, 0],
[0, 65],
[12, 34, 56],
[0, 50, 100, 150, 200, 250]
];

console.log("starting tests");
tests.forEach(function(v) {
var p = pack(v);
console.log(v, p, unpack(p));
});


And the output to that is:



starting tests
""
[126, 0] "縀" [126, 0]
[0, 65] "A" [0, 65]
[12, 34, 56] "ఢ㠀" [12, 34, 56, 0]
[0, 50, 100, 150, 200, 250] "2撖죺" [0, 50, 100, 150, 200, 250]


So I have a few things I'd like feedback on.




  1. This was the first time I used bitwise operators. Is this how it should be done?

  2. Are there any speed improvements that could be made?

  3. Can you guys think of any way to discard that last 0 byte when encoding then decoding an array with an odd number of bytes? (see test #4)


Thanks.










share|improve this question









$endgroup$




I need to write a function that "packs" an array of bytes (integers between 0 and 255) into a string. I also need to be able to perform the reverse operation, to get my byte array from the string that it was packed into. This needs to be done as fast as possible. Seeing as JavaScript has 16-bit strings, I packed two bytes per character. Here is my code and tests:



function pack(bytes) {
var str = "";
for(var i = 0; i < bytes.length; i += 2) {
var char = bytes[i] << 8;
if (bytes[i + 1])
char |= bytes[i + 1];
str += String.fromCharCode(char);
}
return str;
}

function unpack(str) {
var bytes = ;
for(var i = 0; i < str.length; i++) {
var char = str.charCodeAt(i);
bytes.push(char >>> 8);
bytes.push(char & 0xFF);
}
return bytes;
}

var tests = [
,
[126, 0],
[0, 65],
[12, 34, 56],
[0, 50, 100, 150, 200, 250]
];

console.log("starting tests");
tests.forEach(function(v) {
var p = pack(v);
console.log(v, p, unpack(p));
});


And the output to that is:



starting tests
""
[126, 0] "縀" [126, 0]
[0, 65] "A" [0, 65]
[12, 34, 56] "ఢ㠀" [12, 34, 56, 0]
[0, 50, 100, 150, 200, 250] "2撖죺" [0, 50, 100, 150, 200, 250]


So I have a few things I'd like feedback on.




  1. This was the first time I used bitwise operators. Is this how it should be done?

  2. Are there any speed improvements that could be made?

  3. Can you guys think of any way to discard that last 0 byte when encoding then decoding an array with an odd number of bytes? (see test #4)


Thanks.







javascript optimization strings






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jul 20 '11 at 21:14









Xeon06Xeon06

233136




233136








  • 1




    $begingroup$
    Regarding 3., just add a sentinel to the end of your packed array indicating whether the final byte should be included or not.
    $endgroup$
    – Rafe
    Jul 21 '11 at 5:17










  • $begingroup$
    Good idea. I was gonna have 2 bytes at the beggining indicating length, but that would have limited the length to 65535. Using your method I can have more. Not that I need it, but it's always nice to break barriers.
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:04










  • $begingroup$
    Why on earth would you want to encode bytes on the client side? Seems like it should be something to do on the server.
    $endgroup$
    – Neil
    Jul 21 '11 at 13:14






  • 2




    $begingroup$
    Who said that was client side?
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:52












  • $begingroup$
    I have used this code and there seems to be a problem when passing 0 values to it, they get converted to '' omitted, making it unreliable to pack 32bit floats to a 4 chars. Is there any solution?
    $endgroup$
    – RenegadeMaster88
    Oct 16 '12 at 15:21














  • 1




    $begingroup$
    Regarding 3., just add a sentinel to the end of your packed array indicating whether the final byte should be included or not.
    $endgroup$
    – Rafe
    Jul 21 '11 at 5:17










  • $begingroup$
    Good idea. I was gonna have 2 bytes at the beggining indicating length, but that would have limited the length to 65535. Using your method I can have more. Not that I need it, but it's always nice to break barriers.
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:04










  • $begingroup$
    Why on earth would you want to encode bytes on the client side? Seems like it should be something to do on the server.
    $endgroup$
    – Neil
    Jul 21 '11 at 13:14






  • 2




    $begingroup$
    Who said that was client side?
    $endgroup$
    – Xeon06
    Jul 21 '11 at 13:52












  • $begingroup$
    I have used this code and there seems to be a problem when passing 0 values to it, they get converted to '' omitted, making it unreliable to pack 32bit floats to a 4 chars. Is there any solution?
    $endgroup$
    – RenegadeMaster88
    Oct 16 '12 at 15:21








1




1




$begingroup$
Regarding 3., just add a sentinel to the end of your packed array indicating whether the final byte should be included or not.
$endgroup$
– Rafe
Jul 21 '11 at 5:17




$begingroup$
Regarding 3., just add a sentinel to the end of your packed array indicating whether the final byte should be included or not.
$endgroup$
– Rafe
Jul 21 '11 at 5:17












$begingroup$
Good idea. I was gonna have 2 bytes at the beggining indicating length, but that would have limited the length to 65535. Using your method I can have more. Not that I need it, but it's always nice to break barriers.
$endgroup$
– Xeon06
Jul 21 '11 at 13:04




$begingroup$
Good idea. I was gonna have 2 bytes at the beggining indicating length, but that would have limited the length to 65535. Using your method I can have more. Not that I need it, but it's always nice to break barriers.
$endgroup$
– Xeon06
Jul 21 '11 at 13:04












$begingroup$
Why on earth would you want to encode bytes on the client side? Seems like it should be something to do on the server.
$endgroup$
– Neil
Jul 21 '11 at 13:14




$begingroup$
Why on earth would you want to encode bytes on the client side? Seems like it should be something to do on the server.
$endgroup$
– Neil
Jul 21 '11 at 13:14




2




2




$begingroup$
Who said that was client side?
$endgroup$
– Xeon06
Jul 21 '11 at 13:52






$begingroup$
Who said that was client side?
$endgroup$
– Xeon06
Jul 21 '11 at 13:52














$begingroup$
I have used this code and there seems to be a problem when passing 0 values to it, they get converted to '' omitted, making it unreliable to pack 32bit floats to a 4 chars. Is there any solution?
$endgroup$
– RenegadeMaster88
Oct 16 '12 at 15:21




$begingroup$
I have used this code and there seems to be a problem when passing 0 values to it, they get converted to '' omitted, making it unreliable to pack 32bit floats to a 4 chars. Is there any solution?
$endgroup$
– RenegadeMaster88
Oct 16 '12 at 15:21










4 Answers
4






active

oldest

votes


















14












$begingroup$

function pack(bytes) {
var str = "";
// You could make it faster by reading bytes.length once.
for(var i = 0; i < bytes.length; i += 2) {
// If you're using signed bytes, you probably need to mask here.
var char = bytes[i] << 8;
// (undefined | 0) === 0 so you can save a test here by doing
// var char = (bytes[i] << 8) | (bytes[i + 1] & 0xff);
if (bytes[i + 1])
char |= bytes[i + 1];
// Instead of using string += you could push char onto an array
// and take advantage of the fact that String.fromCharCode can
// take any number of arguments to do
// String.fromCharCode.apply(null, chars);
str += String.fromCharCode(char);
}
return str;
}

function unpack(str) {
var bytes = ;
for(var i = 0; i < str.length; i++) {
var char = str.charCodeAt(i);
// You can combine both these calls into one,
// bytes.push(char >>> 8, char & 0xff);
bytes.push(char >>> 8);
bytes.push(char & 0xFF);
}
return bytes;
}


so to put it all together



function pack(bytes) {
var chars = ;
for(var i = 0, n = bytes.length; i < n;) {
chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
}
return String.fromCharCode.apply(null, chars);
}

function unpack(str) {
var bytes = ;
for(var i = 0, n = str.length; i < n; i++) {
var char = str.charCodeAt(i);
bytes.push(char >>> 8, char & 0xFF);
}
return bytes;
}





share|improve this answer











$endgroup$









  • 3




    $begingroup$
    Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
    $endgroup$
    – Matthew Caruana Galizia
    Mar 12 '12 at 12:03





















3












$begingroup$

As for the packing loop.... this test over here: http://jsperf.com/string-fromcharcode-test



shows that:



var s = "";
for(var i=0,l=chars.length; i<l; i++)
s += String.fromCharCode(chars[i]);


is faster than:



var s = String.fromCharCode.apply(null, chars);





share|improve this answer









$endgroup$





















    0












    $begingroup$

    building on what @mike & @nik have said, here's the pack function:



    function pack(bytes) {
    var retStr = '';
    var char, i, l;
    for (var i = 0, l = bytes.length; i < l;) {
    char = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
    retStr += String.fromCharCode(char);
    }
    return retStr;
    }





    share|improve this answer









    $endgroup$





















      0












      $begingroup$

      Nik's test is greate, but today (6 years later) the fastest code is



      var s = String.fromCharCode.apply(null, chars);


      It is 3x faster than for loop! See http://jsperf.com/string-fromcharcode-test.





      share








      New contributor




      Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      $endgroup$













        Your Answer





        StackExchange.ifUsing("editor", function () {
        return StackExchange.using("mathjaxEditing", function () {
        StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
        StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
        });
        });
        }, "mathjax-editing");

        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "196"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f3569%2fpack-and-unpack-bytes-to-strings%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        14












        $begingroup$

        function pack(bytes) {
        var str = "";
        // You could make it faster by reading bytes.length once.
        for(var i = 0; i < bytes.length; i += 2) {
        // If you're using signed bytes, you probably need to mask here.
        var char = bytes[i] << 8;
        // (undefined | 0) === 0 so you can save a test here by doing
        // var char = (bytes[i] << 8) | (bytes[i + 1] & 0xff);
        if (bytes[i + 1])
        char |= bytes[i + 1];
        // Instead of using string += you could push char onto an array
        // and take advantage of the fact that String.fromCharCode can
        // take any number of arguments to do
        // String.fromCharCode.apply(null, chars);
        str += String.fromCharCode(char);
        }
        return str;
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0; i < str.length; i++) {
        var char = str.charCodeAt(i);
        // You can combine both these calls into one,
        // bytes.push(char >>> 8, char & 0xff);
        bytes.push(char >>> 8);
        bytes.push(char & 0xFF);
        }
        return bytes;
        }


        so to put it all together



        function pack(bytes) {
        var chars = ;
        for(var i = 0, n = bytes.length; i < n;) {
        chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
        }
        return String.fromCharCode.apply(null, chars);
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0, n = str.length; i < n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char >>> 8, char & 0xFF);
        }
        return bytes;
        }





        share|improve this answer











        $endgroup$









        • 3




          $begingroup$
          Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
          $endgroup$
          – Matthew Caruana Galizia
          Mar 12 '12 at 12:03


















        14












        $begingroup$

        function pack(bytes) {
        var str = "";
        // You could make it faster by reading bytes.length once.
        for(var i = 0; i < bytes.length; i += 2) {
        // If you're using signed bytes, you probably need to mask here.
        var char = bytes[i] << 8;
        // (undefined | 0) === 0 so you can save a test here by doing
        // var char = (bytes[i] << 8) | (bytes[i + 1] & 0xff);
        if (bytes[i + 1])
        char |= bytes[i + 1];
        // Instead of using string += you could push char onto an array
        // and take advantage of the fact that String.fromCharCode can
        // take any number of arguments to do
        // String.fromCharCode.apply(null, chars);
        str += String.fromCharCode(char);
        }
        return str;
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0; i < str.length; i++) {
        var char = str.charCodeAt(i);
        // You can combine both these calls into one,
        // bytes.push(char >>> 8, char & 0xff);
        bytes.push(char >>> 8);
        bytes.push(char & 0xFF);
        }
        return bytes;
        }


        so to put it all together



        function pack(bytes) {
        var chars = ;
        for(var i = 0, n = bytes.length; i < n;) {
        chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
        }
        return String.fromCharCode.apply(null, chars);
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0, n = str.length; i < n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char >>> 8, char & 0xFF);
        }
        return bytes;
        }





        share|improve this answer











        $endgroup$









        • 3




          $begingroup$
          Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
          $endgroup$
          – Matthew Caruana Galizia
          Mar 12 '12 at 12:03
















        14












        14








        14





        $begingroup$

        function pack(bytes) {
        var str = "";
        // You could make it faster by reading bytes.length once.
        for(var i = 0; i < bytes.length; i += 2) {
        // If you're using signed bytes, you probably need to mask here.
        var char = bytes[i] << 8;
        // (undefined | 0) === 0 so you can save a test here by doing
        // var char = (bytes[i] << 8) | (bytes[i + 1] & 0xff);
        if (bytes[i + 1])
        char |= bytes[i + 1];
        // Instead of using string += you could push char onto an array
        // and take advantage of the fact that String.fromCharCode can
        // take any number of arguments to do
        // String.fromCharCode.apply(null, chars);
        str += String.fromCharCode(char);
        }
        return str;
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0; i < str.length; i++) {
        var char = str.charCodeAt(i);
        // You can combine both these calls into one,
        // bytes.push(char >>> 8, char & 0xff);
        bytes.push(char >>> 8);
        bytes.push(char & 0xFF);
        }
        return bytes;
        }


        so to put it all together



        function pack(bytes) {
        var chars = ;
        for(var i = 0, n = bytes.length; i < n;) {
        chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
        }
        return String.fromCharCode.apply(null, chars);
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0, n = str.length; i < n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char >>> 8, char & 0xFF);
        }
        return bytes;
        }





        share|improve this answer











        $endgroup$



        function pack(bytes) {
        var str = "";
        // You could make it faster by reading bytes.length once.
        for(var i = 0; i < bytes.length; i += 2) {
        // If you're using signed bytes, you probably need to mask here.
        var char = bytes[i] << 8;
        // (undefined | 0) === 0 so you can save a test here by doing
        // var char = (bytes[i] << 8) | (bytes[i + 1] & 0xff);
        if (bytes[i + 1])
        char |= bytes[i + 1];
        // Instead of using string += you could push char onto an array
        // and take advantage of the fact that String.fromCharCode can
        // take any number of arguments to do
        // String.fromCharCode.apply(null, chars);
        str += String.fromCharCode(char);
        }
        return str;
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0; i < str.length; i++) {
        var char = str.charCodeAt(i);
        // You can combine both these calls into one,
        // bytes.push(char >>> 8, char & 0xff);
        bytes.push(char >>> 8);
        bytes.push(char & 0xFF);
        }
        return bytes;
        }


        so to put it all together



        function pack(bytes) {
        var chars = ;
        for(var i = 0, n = bytes.length; i < n;) {
        chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
        }
        return String.fromCharCode.apply(null, chars);
        }

        function unpack(str) {
        var bytes = ;
        for(var i = 0, n = str.length; i < n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char >>> 8, char & 0xFF);
        }
        return bytes;
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jul 22 '11 at 0:21

























        answered Jul 22 '11 at 0:13









        Mike SamuelMike Samuel

        546612




        546612








        • 3




          $begingroup$
          Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
          $endgroup$
          – Matthew Caruana Galizia
          Mar 12 '12 at 12:03
















        • 3




          $begingroup$
          Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
          $endgroup$
          – Matthew Caruana Galizia
          Mar 12 '12 at 12:03










        3




        3




        $begingroup$
        Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
        $endgroup$
        – Matthew Caruana Galizia
        Mar 12 '12 at 12:03






        $begingroup$
        Note that String.fromCharCode.apply(null, chars); will throw a "RangeError: Maximum call stack size exceeded" exception in browsers using JavaScriptCore (i.e. Safari) if chars has a length greater than 65536, and will lock up completely on arrays slightly smaller than that. A complete solution would either push the string directly into the array or use a chunked version of fromCharCode. I suspect the former is faster in Safari. See bugs.webkit.org/show_bug.cgi?id=80797
        $endgroup$
        – Matthew Caruana Galizia
        Mar 12 '12 at 12:03















        3












        $begingroup$

        As for the packing loop.... this test over here: http://jsperf.com/string-fromcharcode-test



        shows that:



        var s = "";
        for(var i=0,l=chars.length; i<l; i++)
        s += String.fromCharCode(chars[i]);


        is faster than:



        var s = String.fromCharCode.apply(null, chars);





        share|improve this answer









        $endgroup$


















          3












          $begingroup$

          As for the packing loop.... this test over here: http://jsperf.com/string-fromcharcode-test



          shows that:



          var s = "";
          for(var i=0,l=chars.length; i<l; i++)
          s += String.fromCharCode(chars[i]);


          is faster than:



          var s = String.fromCharCode.apply(null, chars);





          share|improve this answer









          $endgroup$
















            3












            3








            3





            $begingroup$

            As for the packing loop.... this test over here: http://jsperf.com/string-fromcharcode-test



            shows that:



            var s = "";
            for(var i=0,l=chars.length; i<l; i++)
            s += String.fromCharCode(chars[i]);


            is faster than:



            var s = String.fromCharCode.apply(null, chars);





            share|improve this answer









            $endgroup$



            As for the packing loop.... this test over here: http://jsperf.com/string-fromcharcode-test



            shows that:



            var s = "";
            for(var i=0,l=chars.length; i<l; i++)
            s += String.fromCharCode(chars[i]);


            is faster than:



            var s = String.fromCharCode.apply(null, chars);






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Feb 23 '13 at 12:44









            Nik AhmadNik Ahmad

            311




            311























                0












                $begingroup$

                building on what @mike & @nik have said, here's the pack function:



                function pack(bytes) {
                var retStr = '';
                var char, i, l;
                for (var i = 0, l = bytes.length; i < l;) {
                char = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
                retStr += String.fromCharCode(char);
                }
                return retStr;
                }





                share|improve this answer









                $endgroup$


















                  0












                  $begingroup$

                  building on what @mike & @nik have said, here's the pack function:



                  function pack(bytes) {
                  var retStr = '';
                  var char, i, l;
                  for (var i = 0, l = bytes.length; i < l;) {
                  char = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
                  retStr += String.fromCharCode(char);
                  }
                  return retStr;
                  }





                  share|improve this answer









                  $endgroup$
















                    0












                    0








                    0





                    $begingroup$

                    building on what @mike & @nik have said, here's the pack function:



                    function pack(bytes) {
                    var retStr = '';
                    var char, i, l;
                    for (var i = 0, l = bytes.length; i < l;) {
                    char = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
                    retStr += String.fromCharCode(char);
                    }
                    return retStr;
                    }





                    share|improve this answer









                    $endgroup$



                    building on what @mike & @nik have said, here's the pack function:



                    function pack(bytes) {
                    var retStr = '';
                    var char, i, l;
                    for (var i = 0, l = bytes.length; i < l;) {
                    char = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
                    retStr += String.fromCharCode(char);
                    }
                    return retStr;
                    }






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered May 16 '17 at 16:48









                    Brad KentBrad Kent

                    101




                    101























                        0












                        $begingroup$

                        Nik's test is greate, but today (6 years later) the fastest code is



                        var s = String.fromCharCode.apply(null, chars);


                        It is 3x faster than for loop! See http://jsperf.com/string-fromcharcode-test.





                        share








                        New contributor




                        Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.






                        $endgroup$


















                          0












                          $begingroup$

                          Nik's test is greate, but today (6 years later) the fastest code is



                          var s = String.fromCharCode.apply(null, chars);


                          It is 3x faster than for loop! See http://jsperf.com/string-fromcharcode-test.





                          share








                          New contributor




                          Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






                          $endgroup$
















                            0












                            0








                            0





                            $begingroup$

                            Nik's test is greate, but today (6 years later) the fastest code is



                            var s = String.fromCharCode.apply(null, chars);


                            It is 3x faster than for loop! See http://jsperf.com/string-fromcharcode-test.





                            share








                            New contributor




                            Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.






                            $endgroup$



                            Nik's test is greate, but today (6 years later) the fastest code is



                            var s = String.fromCharCode.apply(null, chars);


                            It is 3x faster than for loop! See http://jsperf.com/string-fromcharcode-test.






                            share








                            New contributor




                            Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.








                            share


                            share






                            New contributor




                            Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.









                            answered 4 mins ago









                            CodrCodr

                            11




                            11




                            New contributor




                            Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.





                            New contributor





                            Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.






                            Codr is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Code Review Stack Exchange!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                Use MathJax to format equations. MathJax reference.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f3569%2fpack-and-unpack-bytes-to-strings%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Create new schema in PostgreSQL using DBeaver

                                Deepest pit of an array with Javascript: test on Codility

                                Costa Masnaga