Binary to hex in Python, low-nibble first encoding
<p>I have a protocol that requires converting binary data to and from a hex-encoded string where the low-nibble (lower 4 bits of each byte) come first - so for example the Python string '\xab\xcd' would be encoded as 'badc'. This odd format comes from the PHP/Perl <code>pack</code> and <code>unpack</code> functions with the <code>h*</code> format (see <a href="http://php.net/manual/en/function.pack.php" rel="nofollow">http://php.net/manual/en/function.pack.php</a>). </p>

<p>Obviously plain <code>binascii.hexlify()</code> et al won't achieve this. I've tried using various formats with the <code>struct</code> module as well as <code>array</code> byteswapping <a href="http://stackoverflow.com/questions/13155570/reorder-byte-order-in-hex-string-python">as suggested here</a> but couldn't get it to work. </p>

<p>I ended up solving it with some old-fashioned bit juggling like this: </p>

<pre><code>def to_low_nibble_hex(value):
    """Convert a binary string to hex using low-nibble first encoding
    """
    r = []
    for c in value:
        c = ord(c)
        hb = (0x0f &amp; c) &lt;&lt; 4
        lb = (0xf0 &amp; c) &gt;&gt; 4
        nc = chr(hb | lb)
        r += [nc]
    return binascii.hexlify(''.join(r))
</code></pre>

<p>This seems to work well in my case but I was wondering if anyone can suggest a more formal approach.</p>

<p>A more efficient way would be to precalculate a translation table and then simply apply it using <a href="https://docs.python.org/2/library/string.html#string.translate" rel="nofollow"><code>str.translate()</code></a></p>

<pre><code>_translation = bytearray(((0x0f &amp; c) &lt;&lt; 4 | (0xf0 &amp; c) &gt;&gt; 4)
                         for c in range(256))

def to_low_nibble_hex(value):
    return binascii.hexlify(value.translate(_translation))
</code></pre>

<p>This also works on python3 without modification, although there you could replace <code>bytearray</code> with <code>bytes</code></p>

python encoding hex binary-data packing