二进制与ASCII相互转换

98 投票
8 回答
318233 浏览
提问于 2025-04-17 02:10

这段代码的作用是把一个字符串转换成二进制形式:

bin(reduce(lambda x, y: 256*x+y, (ord(c) for c in 'hello'), 0))

运行后会输出:

0b110100001100101011011000110110001101111

如果我把这个输出放到这个网站(在右侧),我就能得到我的消息hello。我在想这个网站是用什么方法来实现的。我知道我可以把二进制字符串分成8位一组,然后把每组和bin(ord(character))对应起来,或者用其他方法。但我其实想找一个更简单的办法。

8 个回答

10

我不太明白你除了逐个字符处理之外,还能怎么做——这本质上就是一个逐个字符的操作。网上确实有代码可以帮你完成这个,但没有比逐个字符处理更简单的方法。

首先,你需要去掉 0b 前缀,然后在字符串左边补零,使得字符串的长度可以被8整除,这样方便把位字符串分成字符:

bitstring = bitstring[2:]
bitstring = -len(bitstring) % 8 * '0' + bitstring

接着,你把字符串分成八个二进制数字一组,转换成ASCII字符,然后再把它们拼接成一个字符串:

string_blocks = (bitstring[i:i+8] for i in range(0, len(bitstring), 8))
string = ''.join(chr(int(char, 2)) for char in string_blocks)

如果你真的想把它当作一个数字来处理,你还得考虑到,如果你想从左到右读取,最左边的字符最多只能有七位。

33

内置 仅限 python

这里有一个纯粹用python写的方法,适用于简单的字符串,留在这里以供后人参考。

def string2bits(s=''):
    return [bin(ord(x))[2:].zfill(8) for x in s]

def bits2string(b=None):
    return ''.join([chr(int(x, 2)) for x in b])

s = 'Hello, World!'
b = string2bits(s)
s2 = bits2string(b)

print 'String:'
print s

print '\nList of Bits:'
for x in b:
    print x

print '\nString:'
print s2

String:
Hello, World!

List of Bits:
01001000
01100101
01101100
01101100
01101111
00101100
00100000
01010111
01101111
01110010
01101100
01100100
00100001

String:
Hello, World!
177

对于Python 2中范围为[ -~]的ASCII字符:

>>> import binascii
>>> bin(int(binascii.hexlify('hello'), 16))
'0b110100001100101011011000110110001101111'

反向操作:

>>> n = int('0b110100001100101011011000110110001101111', 2)
>>> binascii.unhexlify('%x' % n)
'hello'

在Python 3.2及以上版本:

>>> bin(int.from_bytes('hello'.encode(), 'big'))
'0b110100001100101011011000110110001101111'

反向操作:

>>> n = int('0b110100001100101011011000110110001101111', 2)
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big').decode()
'hello'

在Python 3中支持所有Unicode字符:

def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
    bits = bin(int.from_bytes(text.encode(encoding, errors), 'big'))[2:]
    return bits.zfill(8 * ((len(bits) + 7) // 8))

def text_from_bits(bits, encoding='utf-8', errors='surrogatepass'):
    n = int(bits, 2)
    return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors) or '\0'

这里有一个兼容Python 2和3的单一版本:

import binascii

def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
    bits = bin(int(binascii.hexlify(text.encode(encoding, errors)), 16))[2:]
    return bits.zfill(8 * ((len(bits) + 7) // 8))

def text_from_bits(bits, encoding='utf-8', errors='surrogatepass'):
    n = int(bits, 2)
    return int2bytes(n).decode(encoding, errors)

def int2bytes(i):
    hex_string = '%x' % i
    n = len(hex_string)
    return binascii.unhexlify(hex_string.zfill(n + (n & 1)))

示例

>>> text_to_bits('hello')
'0110100001100101011011000110110001101111'
>>> text_from_bits('110100001100101011011000110110001101111') == u'hello'
True

撰写回答