Skip to content

Instantly share code, notes, and snippets.

@mzpqnxow
Last active April 9, 2023 20:19
Show Gist options
  • Save mzpqnxow/a368c6cd9fae97b87ef25f475112c84c to your computer and use it in GitHub Desktop.
Save mzpqnxow/a368c6cd9fae97b87ef25f475112c84c to your computer and use it in GitHub Desktop.
Python3 bytes to ASCII hexdump function using format
def hexdump(src, length=16, sep='.'):
"""Hex dump bytes to ASCII string, padded neatly
In [107]: x = b'\x01\x02\x03\x04AAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBB'
In [108]: print('\n'.join(hexdump(x)))
00000000 01 02 03 04 41 41 41 41 41 41 41 41 41 41 41 41 |....AAAAAAAAAAAA|
00000010 41 41 41 41 41 41 41 41 41 41 41 41 41 41 42 42 |AAAAAAAAAAAAAABB|
00000020 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 |BBBBBBBBBBBBBBBB|
00000030 42 42 42 42 42 42 42 42 |BBBBBBBB |
"""
FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or sep for x in range(256)])
lines = []
for c in range(0, len(src), length):
chars = src[c: c + length]
hex_ = ' '.join(['{:02x}'.format(x) for x in chars])
if len(hex_) > 24:
hex_ = '{} {}'.format(hex_[:24], hex_[24:])
printable = ''.join(['{}'.format((x <= 127 and FILTER[x]) or sep) for x in chars])
lines.append('{0:08x} {1:{2}s} |{3:{4}s}|'.format(c, hex_, length * 3, printable, length))
return lines
@FalcoGer
Copy link

I find this hard to read. I have fixed the grouping error that occurs when increasing the length and I also added a group size parameter.

def hexdump(src: bytes, bytesPerLine: int = 16, bytesPerGroup: int = 4, sep: str = '.'):
    FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or sep for x in range(256)])
    lines = []
    maxAddrLen = len(hex(len(src)))
    if 8 > maxAddrLen:
        maxAddrLen = 8

    for addr in range(0, len(src), bytesPerLine):
        hexString = ""
        printable = ""

        # The chars we need to process for this line
        chars = src[addr : addr + bytesPerLine]

        # Create hex string
        tmp = ''.join(['{:02X}'.format(x) for x in chars])
        idx = 0
        for c in tmp:
            hexString += c
            idx += 1
            # 2 hex digits per byte.
            if idx % bytesPerGroup * 2 == 0 and idx < bytesPerLine * 2:
                hexString += " "
        # Pad out the line to fill up the line to take up the right amount of space to line up with a full line.
        hexString = hexString.ljust(bytesPerLine * 2 + int(bytesPerLine * 2 / bytesPerGroup) - 1)

        # create printable string
        tmp = ''.join(['{}'.format((x <= 127 and FILTER[x]) or sep) for x in chars])
        # insert space every bytesPerGroup
        idx = 0
        for c in tmp:
            printable += c
            idx += 1
            # Need to check idx because strip() would also delete genuine spaces that are in the data.
            if idx % bytesPerGroup == 0 and idx < len(chars):
                printable += " "

        lines.append(f'{addr:0{maxAddrLen}X}  {hexString}  |{printable}|')
    return lines

@mzpqnxow
Copy link
Author

mzpqnxow commented Apr 9, 2023

Thanks-, yes it was gross- and thanks for adding the PEP-484 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment