Das Ergebnis hängt von der Codierung verwendet wird, da die Anzahl der Bytes pro Zeichen eine Funktion der Codierung ist, und in vielen Codierungen des Charakter auch. Ich nehme an, wir verwenden UTF-8, in dem '☺'
ist codiert als e298ba
und ist drei Bytes lang; Das gegebene Beispiel ist konsistent mit dieser Annahme.
Alles in textwrap
funktioniert auf Zeichen; es weiß nichts über Kodierungen. Eine Möglichkeit besteht darin, die Eingabezeichenfolge in ein anderes Format zu konvertieren, wobei jedes Zeichen eine Zeichenfolge wird, deren Länge proportional zur Bytelänge ist. Ich werde drei Zeichen verwenden: zwei für das Byte in Hex, plus eins, um Zeilenumbruch zu steuern. So :
'a' -> '61x' non-breaking
' ' -> '20 ' breaking
'☺' -> 'e2x98xbax' non-breaking
Der Einfachheit halber nehme an, ich, dass wir nur auf Räume brechen, nicht Tabs oder jede anderen Charakter.
import textwrap
def wrapbytes(s, bytewidth, encoding='utf-8', show_work=False):
byts = s.encode(encoding)
encoded = ''.join('{:02x}{}'.format(b, ' ' if b in b' ' else 'x')
for b in byts)
if show_work:
print('encoded = {}\n'.format(encoded))
ewidth = bytewidth * 3 + 2
elist = textwrap.wrap(encoded, width=ewidth)
if show_work:
print('elist = {}\n'.format(elist))
# Remove trailing encoded spaces.
elist = [s[:-2] if s[-2:] == '20' else s for s in elist]
if show_work:
print('elist = {}\n'.format(elist))
# Decode. Method 1: inefficient and lengthy, but readable.
bl1 = []
for s in elist:
bstr = "b'"
for i in range(0, len(s), 3):
hexchars = s[i:i+2]
b = r'\x' + hexchars
bstr += b
bstr += "'"
bl1.append(eval(bstr))
# Method 2: equivalent, efficient, terse, hard to read.
bl2 = [eval("b'{}'".format(''.join(r'\x{}'.format(s[i:i+2])
for i in range(0, len(s), 3))))
for s in elist]
assert(bl1 == bl2)
if show_work:
print('bl1 = {}\n'.format(bl1))
dlist = [b.decode(encoding) for b in bl1]
if show_work:
print('dlist = {}\n'.format(dlist))
return(dlist)
result = wrapbytes('☺ ☺☺ ☺☺ ☺ ☺ ☺☺ ☺☺', bytewidth=10, show_work=True)
print('\n'.join(result))