将数字转换为二进制并保留前导零

235

我在尝试使用Python中的bin()函数将整数转换为二进制。然而,它总是会删除前导零,而我实际上需要保留前导零,以便结果始终为8位:

示例:

bin(1) -> 0b1

# What I would like:
bin(1) -> 0b00000001

有没有一种方法可以做到这一点?


参见:Python int to binary?,特别是使用n位表示的我的答案。虽然不完全相同,但我在寻找我的答案时来到了这个问题... - Martin Thoma
11个回答

344

使用format()函数:

>>> format(14, '#010b')
'0b00001110'
format()函数简单地按照格式规范迷你语言格式化输入。 #使格式包括0b前缀,而010大小格式将输出格式化为10个字符宽度,使用0填充; 2个字符用于0b前缀,其余8个字符用于二进制数字。

这是最紧凑和直接的选项。

如果您要将结果放入较大的字符串中,请使用格式化字符串字面值(3.6+)或使用 str.format()并在占位符{:..}的冒号后放置format()函数的第二个参数:

>>> value = 14
>>> f'The produced output, in binary, is: {value:#010b}'
'The produced output, in binary, is: 0b00001110'
>>> 'The produced output, in binary, is: {:#010b}'.format(value)
'The produced output, in binary, is: 0b00001110'

事实上,即使只是格式化单个值(而不将结果放入较大的字符串中),使用格式化字符串字面量比使用format()更快:

事实上,即使只是格式化单个值(而不将结果放入较大的字符串中),使用格式化字符串字面量比使用format()更快:
>>> import timeit
>>> timeit.timeit("f_(v, '#010b')", "v = 14; f_ = format")  # use a local for performance
0.40298633499332936
>>> timeit.timeit("f'{v:#010b}'", "v = 14")
0.2850222919951193

但是只有在需要在紧密循环中考虑性能时,我才会使用它,因为format(...)更能传达意图。

如果您不想要0b前缀,只需省略#并调整字段的长度:

>>> format(14, '08b')
'00001110'

5
我找到了我需要的内容,这种格式对我非常有帮助。我开始学习位运算,并且在谷歌上搜索Python中数字的位格式。找到了这个。谢谢你。 - kratostoical
@tjt263:这就是为什么我明确指出如果您要将结果放入较大的字符串中,请使用格式化字符串字面值(3.6+)或使用str.format(),并在占位符{:..}的冒号后放置format()函数的第二个参数: - Martijn Pieters
2
例如使用 f"{192:08b}.{0:08b}.{2:08b}.{33:08b}" - Martijn Pieters
@MartijnPieters 如果我想要位数可变的变量呢?例如你使用了 format(14, '08b') 但是我需要在那里用可变的x。 - efe373
@efe373:你可以格式化第二个参数,它只是一个字符串。例如:format(14, f"0{x}b")。或者将其合并为单个格式化字符串,f"{14:0{x}b}" - Martijn Pieters
显示剩余2条评论

144
>>> '{:08b}'.format(1)
'00000001'

请参见:格式规范微语言


对于 Python 2.6 或更早版本,您不能省略冒号前的位置参数标识符,因此请使用:

>>> '{0:08b}'.format(1)
'00000001'      

3
这里不需要使用 str.format(),直接使用 format() 即可。你漏掉了 0b 前缀。 - Martijn Pieters
2
@MartijnPieters,str.formatformat()更灵活,因为它允许您同时处理多个变量。我总是忘记format函数的存在。不过,必须承认,在这种情况下,它完全足够了。 - Mark Ransom
1
@MarkRansom:没错,当你只使用 str.format() 并且只有一个 {} 元素时,没有其他文本,你不是在使用字符串模板,而是在格式化一个值。在这种情况下,只需使用 format()。 :-) - Martijn Pieters
这段代码不再适用: print("TCP: Option: Data: {:08b}".format(option_data)) TypeError: 未支持元组.__format__传递的格式化字符串 - wheeler

47

我正在使用

bin(1)[2:].zfill(8)

将会打印

'00000001'

11

当使用Python >= 3.6时,您可以使用f字符串字符串格式化

>>> var = 23
>>> f"{var:#010b}"
'0b00010111'

说明:

  • var:需要格式化的变量。
  • ::冒号后面是格式说明符。
  • #:使用替代格式(添加前缀0b)。
  • 0:用零填充。
  • 10:总长度为10(包括0b这两个字符)。
  • b:使用二进制表示数字。

1
不,它并不是最干净的,除非您对字符串进行更多操作而不仅仅是单个占位符。否则,format(var, "#010b") 可以更好地传达意图。然而,它是最快的选项。但是您已经知道了这一点,因为我在我的答案中已经涵盖了您发布的所有内容 - Martijn Pieters
我同意@MartijnPieters的观点,如果您不需要将其作为较长字符串的一部分,则format更加简洁。 - ruohola

10
您可以使用字符串格式化迷你语言(感谢@Martijn Pieters的建议)思路:
def binary(num, length=8):
    return format(num, '#0{}b'.format(length + 2))

示例:

print(binary(1))

输出:

'0b00000001'

2
相同的格式化语言可以用于包含前缀。使用 #。还有 format(),它可以帮助您避免完整的字符串模板。 - Martijn Pieters

6

我喜欢使用Python的f-string格式化方式,尤其是当需要对参数进行格式化时:

>>> x = 5
>>> n = 8
>>> print(f"{x:0{n}b}")
00000101

这里我使用以下格式打印变量x:我希望它是左填充为0,长度为n,以b(二进制)格式呈现。查看之前的答案中的Format Specification Mini-Language以获取更多信息。


3
有时候你只需要一个简单的一行代码:
binary = ''.join(['{0:08b}'.format(ord(x)) for x in input])

Python 3


2
请注意,[ ] 不是必需的 - join() 函数接受生成器表达式。''.join('{0:08b}'.format(ord(x)) for x in input) - Christoph Burschka
2
注意: 因为str.join()需要两次遍历,所以生成器输入在连接之前首先转换为列表。这对性能有一定的影响,因此在这里传入列表解析比传入生成器表达式更好。这是规则中的一个例外。 - Martijn Pieters

0

虽然有很多解决方案已经在这里和那里发布了,但最快的方法(如果你不需要前面的'0b'部分)是将f'{x:'b'}'与.zfill(n)组合起来进行填充。

即使你想要前导的'0b',也可以通过使用以下代码添加:

'0b'+f'{i:b}'.zfill(n)

它仍然比使用f"{x:0{n}b}"方法更快且更易读。

这里找到相关的基准测试代码和结果。


-1
你可以使用类似这样的代码:
("{:0%db}"%length).format(num)

2
请至少为您的代码片段使用代码块。如果您真的希望它成为一个好答案,那么还应该添加一些注释,说明这个解决方案是如何解决 OP 的问题的。 - β.εηοιτ.βε
你不需要使用不同的字符串格式化样式来添加变量宽度。只需添加另一个占位符:"{:0{l}b}".format(num, l=length) - Martijn Pieters

-3
你可以使用 zfill:
print str(1).zfill(2) 
print str(10).zfill(2) 
print str(100).zfill(2)

输出:

01
10
100

我喜欢这个解决方案,因为它不仅在输出数字时有用,而且在需要将其分配给变量时也很有帮助...例如 - x = str(datetime.date.today().month).zfill(2) 将返回 '02' 作为二月份的月份。


1
zfill存在的问题是它将二进制字符串视为字符串,并在二进制'b'指示符之前添加零...例如bin(14)
得到 '0b1110'

bin(14).zfill(8)
得到
'000b1110' 而不是 '0b00001110' 这就是所需的。
- Shaun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接