在Python中将整数转换为二进制字符串

807

如何在Python中将整数转换为二进制字符串?

37   →   '100101'

对于相反的方法,请参见纯字符串处理算法此处 - CopyPasteIt
36个回答

1066

152
仅为格式化一个值而使用str.format()是过度的。直接使用format() 函数format(n, 'b')。无需解析占位符并将其与参数匹配,直接进行值格式化操作。仅当您需要将格式化后的结果放入较长的字符串中(例如将其用作模板)时,请使用 str.format() - Martijn Pieters
57
您可以使用格式规范来添加前导0并将数字格式化为特定位数。例如,使用字符串格式化函数format(10, '016b')可以将数字10格式化为16位带前导零的二进制数。请注意,不要改变原文意思。 - Martijn Pieters
在这种情况下,"{0:b}" 中的 0 可以省略,对吧?我的意思是,在只格式化一个数字的情况下,把 "{:b}" 放进去是正确的,不是吗? - tomasyany
7
通常使用4/8/...位表示法:"{:08b}".format(37) - Sparkler
19
Python 3.7及以上版本中的代码"f"{37:b}",意思是将数字37转化为二进制并以字符串形式输出。 - D. A.
5
这里存在一个关于负数的问题。@nate没有清楚地指定在这种情况下所需的输出是什么,但在二进制数字中,负号不存在。因此,最高有效位通常用于表示负号。假设我们使用8位整数,-37将为0b10100101。但在无符号整数中,该值将为165。因此,情况并不像这么简单。答案应反映出这一点。 - Dolf Andringa

649
如果你想要一个与hex()等价的bin()函数,它在Python 2.6中被添加。
示例:
>>> bin(10)
'0b1010'

103
注意,使用 str(bin(i))[2:] (1000000次操作只需0.369秒) 比使用 "{0:b}".format(i) (1000000次操作需要0.721秒) 更快。 - mVChr
89
如果有人将数字转换为ASCII二进制表示法,我真的希望速度不要太慢。 - Nick T
41
str.format() 不是正确的工具,你应该使用 format(i, 'b')。注意,这也提供了填充和对齐选项。若要将其格式化为16位零填充二进制数,可以使用 format(i, '016b')。如果要使用 bin() 实现相同的效果,则需要添加 str.zfill() 调用:bin(i)[2:].zfill(16)(不需要调用 str()!)。format() 的可读性和灵活性优于 bin(),动态格式化与 bin() 相比更加困难。在不必要的情况下,不要以性能为最优,而要以易维护性为最优。 - Martijn Pieters
[2:] 是什么意思? - zero_cool
14
当然,使用 Python 3.6 及以上版本,你现在可以使用 f"{37:b}" - Luke Davis
@MartijnPieters - “除非必须,否则不要为性能进行优化,而是应该优化可维护性” - 说得好。 - user3481644

72

实际上,Python内置了处理这种情况的功能,使用像'{0:b}'.format(42)这样的操作可以给出一个字符串形式的位模式,并输出42的二进制表示即101010


对于更一般的哲学问题,没有任何一种语言或库能够满足所有用户需要。如果你在一个不能提供完全符合需求的环境中工作,应该在开发过程中收集代码片段,以确保你不必重复编写同样的代码。例如,伪代码如下:

define intToBinString, receiving intVal:
    if intVal is equal to zero:
        return "0"
    set strVal to ""
    while intVal is greater than zero:
        if intVal is odd:
            prefix "1" to strVal
        else:
            prefix "0" to strVal
        divide intVal by two, rounding down
    return strVal

这段伪代码将根据十进制值构建二进制字符串。请记住,这只是通用的伪代码,可能不是最有效的方法,但考虑到您所提议的迭代次数,这并不会有太大影响。它真的只是作为一个指南,展示如何完成。

总体思路是使用以下代码(按优先级排序):

  • 语言或内置库。
  • 具有适当许可证的第三方库。
  • 您自己的集合。
  • 您需要编写的新内容(并保存在您自己的集合中以供以后使用)。

1
这个答案提供了一些好的建议。只可惜代码不必要地慢。你提出了一个O(N^2)的算法,而O(N)的算法就足够了。问题在于s = "1" + ss = "0" + s这两行代码。每一行都会无谓地复制s。相反,你应该在返回字符串之前将其反转。 - Andreas Magnusson
@Andreas,我建议使用'{0:b}'.format(42),慢速方法只是一个通用方法的示例,具体取决于实际使用的语言,可能是O(n^2),也可能不是。它看起来像Python,因为Python是一种理想的伪代码语言,所以我会更改它以使其清晰明了。 - paxdiablo
实际上,如果s是字符串类型,那么s =“1”+ s不是O(N)的语言可能会相当晦涩难懂。也许是一种所有字符串都是反向存储或每个字符都是链表中的节点的语言?对于任何典型的语言,字符串基本上是字符数组。在这种情况下,前缀字符串需要进行复制,否则你怎么能把字符放在其他字符之前呢? - Andreas Magnusson
我可以轻易地想象出一个字符串类型,它由一块内存组成,在该块内存中,字符串右对齐,并有一个指向其起始字符的偏移量。要在前缀添加一个字符,您只需减少偏移量并将字符存储在那里即可。是的,这可能有点玄学,但是对于我来说,争论一些伪代码可能存在的现实问题没有多大意义,特别是当您不太可能拥有超过几十个位/迭代。即使是备受诟病的冒泡排序,如果您的数据大小很小,也足够了 :-) 无论如何,我会添加一条关于效率的注释。 - paxdiablo
如果效率很重要,你可能不会选择Python。但是在我的经验中,经常发生这样的情况:使用O(N²)算法天真地编写代码并使用小数据集进行测试,然后很快就会使用更大的数据集,因为“它似乎可以工作”。突然间,你会发现代码运行需要几个小时,而修复后可能只需要几秒钟。O(N²)算法是隐蔽的,因为它们似乎可以工作一段时间,但当你的数据规模扩大时,它们就无法胜任了,而此时编写它们的人已经离职,没有人知道为什么事情需要花费很长时间。 - Andreas Magnusson
不必使用if-else语句,您可以直接添加提醒:将prefix(intVal%2)添加到strVal中我知道这个线程已经超过三年了,我并不是为了争论而写这篇文章。我喜欢将算法分解成简化的示例。这只是我的个人意见。 :-) - Thomas Gabrielsen

63

如果你想要一个没有0b前缀的文本表示,你可以使用这个:

get_bin = lambda x: format(x, 'b')

print(get_bin(3))
>>> '11'

print(get_bin(-3))
>>> '-11'

当你需要 n 位表示时:

get_bin = lambda x, n: format(x, 'b').zfill(n)
>>> get_bin(12, 32)
'00000000000000000000000000001100'
>>> get_bin(-12, 32)
'-00000000000000000000000000001100'

或者,如果您喜欢使用函数:

def get_bin(x, n=0):
    """
    Get the binary representation of x.

    Parameters
    ----------
    x : int
    n : int
        Minimum number of digits. If x needs less digits in binary, the rest
        is filled with zeros.

    Returns
    -------
    str
    """
    return format(x, 'b').zfill(n)

8
可以使用format(integer, 'b')来实现。bin()是一种调试工具,专门用于生成Python二进制整数字面量语法format()则用于生成特定格式的输出。 - Martijn Pieters
1
@MartijnPieters非常感谢您的提醒。我已经调整了我的解决方案。您是如何知道bin()是一个旨在生成Python二进制整数字面量语法的调试工具呢?我在文档中找不到相关信息。 - Martin Thoma
3
从文件说明中:结果是有效的 Python 表达式。它的目的是生成一个 Python 表达式,而不是生成最终用户的表示形式。对 oct()hex() 同样适用。 - Martijn Pieters
6
更多选择:如果你想让宽度动态化,可以使用 str.format() 或者动态的第二个参数来使用 format(),而不是 str.zfill()'{0:0{1}b}'.format(x, n) 或者 format(b, '0{}b'.format(n)) - Martijn Pieters
这就是为什么我称它为“更多的选择”。 :-) - Martijn Pieters
显示剩余4条评论

61

我惊讶地发现,没有提到使用Python 3.6及更高版本中支持的格式化字符串来实现这一点的好方法。简而言之:

>>> number = 1
>>> f'0b{number:08b}'
'0b00000001'

更长的故事

这是Python 3.6及以上版本中提供的字符串格式化功能:

>>> x, y, z = 1, 2, 3
>>> f'{x} {y} {2*z}'
'1 2 6'

你也可以请求二进制文件:

>>> f'{z:b}'
'11'

指定宽度:

>>> f'{z:8b}'
'      11'

请求零填充:

f'{z:08b}'
'00000011'

并添加公共前缀以表示二进制数:

>>> f'0b{z:08b}'
'0b00000011'

你也可以让 Python 为您添加前缀,但我不太喜欢它,因为您必须考虑前缀的宽度:

>>> f'{z:#010b}'
'0b00000011'

更多信息可在格式化字符串字面值格式规范迷你语言的官方文档中查看。


添加下划线:f'0b{z:09_b}' => '0b0000_0011' - Frederic
关于字节序怎么样?可以改变它吗? - lesolorzanov
这超出了本问题的范围。最重要的是,无论系统的字节序如何,都要以规范的方式编写位制数字,这只是一种实现细节。您可以使用 f'{z:08b}'[::-1] 来实现最不重要字节优先排序,但在我看来,在大多数情况下,这只会导致混淆... - Roman Pavelka
1
f字符串似乎比format()更快。timeit.timeit('f"{2:08b}"', number=10000000) => 1.1823169720000806,而timeit.timeit('format(2,"08b")', number=10000000) => 1.3507722609992925 - Terrance

44

作为参考:

def toBinary(n):
    return ''.join(str(1 & int(n) >> i) for i in range(64)[::-1])

这个函数可以将一个正整数转换为字符串表示形式'1111111111111111111111111111111111111111111111111111111111111111',最大可以转换到18446744073709551615

虽然它可以被修改以服务更大的整数,但可能不像"{0:b}".format()bin()那样方便。


@GarethDavidson 这是哪个版本?将其明确说明可能在以后的谷歌搜索中更有用。 - Wolf
我想它是2.7版本。我怀疑它在3.x版本中是否能正常工作。 - Gareth Davidson

38

这是针对Python 3的,它保留了前导零!

print(format(0, '08b'))

在此输入图像描述


5
我很感激简单的回答。 - reergymerej
3
非常感谢。很遗憾这个答案排名如此靠后。 - hiperbolt
1
太棒了!这正是我在寻找的。 - Charlie 木匠

30

一种简单的方法是使用字符串格式,可以查看这个页面

>> "{0:b}".format(10)
'1010'

如果您希望二进制字符串具有固定的长度,可以使用以下代码:

>> "{0:{fill}8b}".format(10, fill='0')
'00001010'

如果需要使用二进制补码,可以使用以下代码:

'{0:{fill}{width}b}'.format((x + 2**n) % 2**n, fill='0', width=n)

n代表二进制字符串的宽度。


17

使用lambda的一行代码:

>>> binary = lambda n: '' if n==0 else binary(n/2) + str(n%2)

测试:

>>> binary(5)
'101'



编辑:

但是随后 :(

t1 = time()
for i in range(1000000):
     binary(i)
t2 = time()
print(t2 - t1)
# 6.57236599922

相较于

t1 = time()
for i in range(1000000):
    '{0:b}'.format(i)
t2 = time()
print(t2 - t1)
# 0.68017411232

对于0,返回''。但是,0的正常表示不应该是'0'吗? - dietbacon
如果你想看到那个 0 :), 你可以用 '0' 替换 '',但这会在任何数字前面添加一个前导 0。 - Aziz Alto

16

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