Simple way to print binary numbers in groups of nibbles

Question:

To improve readability, I would like to print a binary number in groups of 4 (nibbles), that are separated by an underscore.

For example:

9     => "1001"
60    => "0011_1100"
100   => "0110_0100"
63000 => "1111_0110_0001_1000"

I was wondering if there was perhaps a simple way of doing this?

Asked By: Tjaart

||

Answers:

I have come up with this function:

import math
def bin_nibble(val):
    num_bits = len(format(val, "b"))
    return "_".join(reversed([format((val>>shift*4)&0x0F, "04b") 
        for shift in range(math.ceil(num_bits/4))]))
Answered By: Tjaart

Try:

def bin_nibble(val):
    b = bin(val)[2:]
    new_b =  '_'.join([b[::-1][i:i+4][::-1] for i in range(0, len(b), 4)][::-1])

If you want to add leading zeros:

def bin_nibble(val):
    b = bin(val)[2:]
    new_b = '_'.join([b[::-1][i:i+4][::-1] for i in range(0, len(b), 4)][::-1])
    return ''.join(['0']*(4 - len(b) % 4 if len(b) % 4 != 0 else 0) + [new_b])
Answered By: Neb

Splitting the logic into generating groups of 4 and joining.

def gen(x):
    while x:
        yield bin(x % 16)[2:].zfill(4)
        x >>= 4


def nibble(x):
    return "_".join(gen(x))

Highest to lowest:

def binNibble(num):
    nibb = bin(num)[2:]
    k = 0 if len(nibb)%4 == 0 else 4-len(nibb)%4  # needs zeros?
    nibb = "0"*k + nibb                           # add them here
    return '_'.join(nibb[i:i+4] for i in range(0,len(nibb),4) ) # put _ in


for i in range(0,1152,127):
    print(i,":  ",binNibble(i))

Output:

   0 :   0000
 127 :   0111_1111
 254 :   1111_1110
 381 :   0001_0111_1101
 508 :   0001_1111_1100
 635 :   0010_0111_1011
 762 :   0010_1111_1010
 889 :   0011_0111_1001
1016 :   0011_1111_1000
1143 :   0100_0111_0111

Your examples:

    9 :   1001
   60 :   0011_1100
  100 :   0110_0100
63000 :   1111_0110_0001_1000
Answered By: Patrick Artner

Another approach using str.format:

def bin_nibble(a, pad=4):
    b = '{:b}'.format(a)
    if len(b) % pad:
        b = '0' * (pad - (len(b) % pad)) + b
    return '_'.join(b[k:k+pad] for k in range(0, len(b), pad))

tests = [9, 60, 100, 63000]
for k in tests:
    print(bin_nibble(k))

Output:

1001
0011_1100
0110_0100
1111_0110_0001_1000
Answered By: Chiheb Nexus

@Tjaart, based on your inputs and expected outputs, the following code will work as expected.

Please try it and let me know if it fails for any of your input.

"""
INPUTS AND EXPECTED OUTPUTS:-

    9     => "1001"
    60    => "0011_1100"
    100   => "0110_0100"
    63000 => "1111_0110_0001_1000"
"""
def get_binary(n):
    s = bin(n)[2:]; # Getting binary string

    strs = [];

    while s:
        l = len(s);     # Finding lenght of binary string

        if l > 4:
            strs.insert(0, s[l-4:]);
            s = s[:l-4];
        else:
            l = len(s);
            s = "0"*(4-l) + s;  # If length is not equal to 4 (modify it by adding 0s to front)
            strs.insert(0, s);
            s = "";

    return "_".join(strs);

# EXAMPLE 1
a = 9;
print(get_binary(a)); # 1001

# EXAMPLE 2
b = 60;
print(get_binary(b)); # 0011_1100

# EXAMPLE 3
c = 100;
print(get_binary(c)); # 0110_0100

# EXAMPLE 4
d = 63000;
print(get_binary(d)); # 1111_0110_0001_1000
Answered By: hygull

I believe the simplest way is with format (or f-strings which use format).

>>> format(63000, '019_b')
'1111_0110_0001_1000'

the 019_b means 0-padded, 19-char, "_" nibble separated, binary

If you want the fewest number of nibbles, you may need to do a bit of math to replace the 19 in the formatting or add more padding and string replace any 0000_ with empty string.

E.g. using 039_b for any 32-bit numbers. For 64-bit you would use 079_b and so on.

>>> format(100, '039_b').replace('0000_', '')
'0110_0100
Answered By: JBernardo
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.