创建: 2023-03-31 16:32
更新: 2023-04-03 10:55
https://scz.617.cn/python/202303311632.txt
目录:
☆ 背景介绍
☆ HYS与ChatGPT的对话
☆ HYS的实现
☆ electroniccc的实现
☆ i2s()
☆ 背景介绍
☆ HYS与ChatGPT的对话
这是小侯与ChatGPT的对话,最终收敛了一下,提供了接近原始需求的关键信息。整个过程挺有借鉴意义,收集并展示之。
公众号Markdown显示可能影响阅读,程序员直接拖TXT回本地细看好了。
2023/3/31 17:17:40 hys
实现Python代码,将
b'PKx03x04x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00+'
转换成
b'PK34'+b''*26+b'+'
--------
2023/3/31 17:17:49 ChatGPT
可以使用下面的Python代码
data = b'PKx03x04...x00+'
new_data = data[:4] + b''*26 + data[-1:]
print(new_data)
--------
2023/3/31 17:18:52 hys
上面字符串中的'x00'个数非定值,请修改代码
--------
2023/3/31 17:19:02 ChatGPT
如果该字符串中的x00个数是不定值,那么可以这样
data = b'PKx03x04...x00+'
new_data = data[:4] + b''*(len(data)-6) + data[-2:]
print(new_data)
这里使用了len(data)获取了字符串的长度,并将其减去固定部分的长度(6),即可得到需要填充0的长度。
--------
2023/3/31 17:19:24 hys
完整字符串长度也非定值,请修改代码
--------
2023/3/31 17:19:34 ChatGPT
如果字符串的长度也是不定值,我们可以使用以下代码
data = b'PKx03x04...x00+'
new_data = data[:4] + b''*(len(data)-4-2) + data[-2:]
print(new_data)
此处使用len(data)-4-2计算出需要填充0的长度,其中4为固定部分的长度(即PK34),2为结束符号的长度。
--------
2023/3/31 17:24:06 hys
我的目的是压缩字符串中相同的字符,比如'x00',出现了26次,就压缩为''*26
--------
2023/3/31 17:24:16 ChatGPT
要压缩字符串中相同的字符,可以使用计数器来实现。您可以循环遍历字符串中所有的字符,对于每个字符,都增加一个计数器。当您遇到一个新字符时,将上一个字符和它出现的次数添加到结果字符串中,并将计数器重置为1。
以下是一个Python代码示例,演示如何执行此操作
def compress_string(s):
result = ''
count = 1
prev_char = s[0]
for char in s[1:]:
if char == prev_char:
count += 1
else:
# Add previous character and its count to result string
result += prev_char * count
# Reset counter and previous character
count = 1
prev_char = char
# Add last character and its count to result string
result += prev_char * count
return result
您可以将该函数应用于您的字符串,并查看输出是否符合您的预期。
--------
2023/3/31 17:28:05 hys
修改上面代码将压缩字符修改成压缩byte
--------
2023/3/31 17:28:14 ChatGPT
好的,我来修改一下代码。请注意,虽然byte类型表示压缩后的数据更加精确,但是在使用过程中也需要注意数据类型的转换问题。同时也需要注意解压缩时使用的解压函数要求输入字节数组。以下是修改之后的代码
import zlib
def compress_byte(data):
byte_data = bytes(data, 'utf-8')
compressed_data = zlib.compress(byte_data)
return compressed_data
def decompress_byte(compressed_data):
decompressed_data = zlib.decompress(compressed_data)
str_data = decompressed_data.decode('utf-8')
return str_data
这个函数和原来的函数功能类似,不同的是现在输入的是一个字符串,输出的是一个经过压缩的字节数组。
--------
2023/3/31 17:28:57 hys
目的是压缩byte数组中相同的byte,比如b'x00',出现了26次,就压缩为b''*26
--------
2023/3/31 17:29:16 ChatGPT
明白了,这个可以使用Python中的itertools.groupby()函数来实现。以下是修改后的代码
import itertools
import zlib
def compress_byte(data):
compressed_data = bytearray()
for byte, group in itertools.groupby(data):
count = len(list(group))
if count > 1:
compressed_data.extend(bytes([byte]))
compressed_data.extend(str(count).encode('utf-8'))
else:
compressed_data.extend(bytes([byte])*count)
return zlib.compress(compressed_data)
def decompress_byte(compressed_data):
decompressed_data = zlib.decompress(compressed_data)
data = bytearray()
i = 0
while i < len(decompressed_data):
byte = decompressed_data[i]
if byte not in range(10): # ascii码表中数字的范围是48-57
count_str = ''
while i+1 < len(decompressed_data) and decompressed_data[i+1] in range(48, 58):
count_str += chr(decompressed_data[i+1])
i += 1
count = int(count_str)
data.extend(bytes([byte])*count)
else:
data.append(byte)
i += 1
return bytes(data)
在压缩字节流时,我们对于连续出现的相同字节采用了“字节计数”的方式压缩,即将这个连续段的第一个字节与重复次数编码成一个字节序列存储,这样可以显著减小数据流的大小。
在解压缩时,我们首先对压缩后的数据流进行反压缩,然后对每个字节进行解码。如果遇到一个非数字的字节,说明这是一个未被压缩的字节,我们将其添加到输出数据流中;如果遇到一个数字,说明接下来的若干个字节是重复出现的相同字节,我们根据数字确定它们的重复次数,然后将这些字节依次添加到输出数据流中。
纵观整个对话,有一些经验教训。若用自然语言描述,应尽可能严谨。最开始使用"字符串"这种术语,ChatGPT就按字符串处理,但实际要处理bytes。compress_string虽然不直接满足原始需求,但算法原理已展现出来,不偷懒的话,到这一步已经可以自修改。接下来错误使用术语"压缩byte",致使ChatGPT误以为需要zlib登场。最后一次提问,精确描述了需求,ChatGPT终于抓住要点,指出itertools.groupby(),这是最接近原始需求的关键信息。虽然compress_byte不是我们想要的,但无所谓了,小侯后来用itertools.groupby()写了一个满足原始需求的实现。
☆ HYS的实现
#! /usr/bin/env python
# -*- encoding: utf-8 -*-
#
# ChatGPT
#
# trained by HYS
# modified by scz
#
import itertools, hexdump
#
##########################################################################
#
#
# i是int型
#
def i2s ( i, next=None ) :
if ord( b'r' ) == i :
s = r'r'
elif ord( b'n' ) == i :
s = r'n'
elif ord( b't' ) == i :
s = r't'
elif ord( b'a' ) == i :
s = r'a'
elif ord( b'b' ) == i :
s = r"b"
elif ord( b'f' ) == i :
s = r'f'
elif ord( b'v' ) == i :
s = r'v'
elif ord( b''' ) == i :
s = r"'"
elif ord( b'"' ) == i :
s = r'"'
elif ord( b'\' ) == i :
s = r'\'
elif i >= 0 and i < 8 :
if next is None :
s = r'%u' % i
else :
if next < ord( b'0' ) or next > ord( b'7' ) :
s = r'%u' % i
else :
s = r'x%02x' % i
elif i >= 0x20 and i <= 0x7e :
s = chr( i )
else :
s = r'x%02x' % i
return s
#
# end of i2s
#
#
# [k for k, g in itertools.groupby(b'aaaabbbccd')]
# [list(g) for k, g in itertools.groupby(b'aaaabbbccd')]
#
def repr_ex ( sth ) :
out = []
tmp = "b'"
sth = [list(g) for k, g in itertools.groupby(sth)]
i = 0
while i < len( sth ) :
count = len( sth[i] )
if count > 1 :
if len( tmp ) > 2 :
out.append( tmp + "'" )
tmp = "b'"
out.append( "b'" + i2s( sth[i][0] ) + "'*" + str(count) )
else :
if i+1 < len( sth ) :
tmp += i2s( sth[i][0], sth[i+1][0] )
else :
tmp += i2s( sth[i][0] )
i += 1
#
# end of while
#
if len( tmp ) > 2 :
out.append( tmp + "'" )
return '+'.join( out )
#
# end of repr_ex
#
#
##########################################################################
#
tmp=b'PK34'+b''*26+b'+(xcaxcc+xd1Pxf7Hxcd'+b'xc9'*2+b'Wbxcf/xcaIQTxd74PK12'+b''*6+b'1'+b''*9+b'x17'+b''*7+b'v'+b''*17+b'_'*2+b'main'+b'_'*2+b'.pyPK56'+b''*8+b'9'+b''*3+b'5'+b''*3
hexdump.hexdump( tmp )
print( repr_ex( tmp ) )
hexdump.hexdump( eval( repr_ex( tmp ) ) )
#
# other test case
#
tmp=b'abcabcx7fvvvf'
tmp=b'0aabcc'
tmp=b'x0057'
☆ electroniccc的实现
这是某网友见题后自己给出的实现
#! /usr/bin/env python
# -*- encoding: utf-8 -*-
#
# https://gist.github.com/electroniccc/af0ff26740533c001886491ad67d04e3
#
# modified by scz
#
import hexdump
#
##########################################################################
#
#
# i是int型
#
def i2s ( i, next=None ) :
if ord( b'r' ) == i :
s = r'r'
elif ord( b'n' ) == i :
s = r'n'
elif ord( b't' ) == i :
s = r't'
elif ord( b'a' ) == i :
s = r'a'
elif ord( b'b' ) == i :
s = r"b"
elif ord( b'f' ) == i :
s = r'f'
elif ord( b'v' ) == i :
s = r'v'
elif ord( b''' ) == i :
s = r"'"
elif ord( b'"' ) == i :
s = r'"'
elif ord( b'\' ) == i :
s = r'\'
elif i >= 0 and i < 8 :
if next is None :
s = r'%u' % i
else :
if next < ord( b'0' ) or next > ord( b'7' ) :
s = r'%u' % i
else :
s = r'x%02x' % i
elif i >= 0x20 and i <= 0x7e :
s = chr( i )
else :
s = r'x%02x' % i
return s
#
# end of i2s
#
def repr_ex ( sth ) :
ret = ''
i = 0
tmp = "b'"
while i < len( sth ) :
j = i + 1
for k in range( i+1, len( sth )+1 ) :
if k == len( sth ) or sth[k] != sth[i] :
j = k
break
#
# end of for
#
if 1 == j - i :
if j < len( sth ) :
tmp += i2s( sth[i], sth[j] )
else :
tmp += i2s( sth[i] )
i += 1
else:
if len( tmp ) > 2 :
tmp += "'"
ret += '+' + tmp
tmp = "b'"
#
# end of if
#
ret += "+b'" + i2s( sth[i] ) + "'*" + str(j-i)
i = j
#
# end of while
#
if len( tmp ) > 2 :
tmp += "'"
ret += '+' + tmp
return ret[1:]
#
# end of repr_ex
#
#
##########################################################################
#
def repr_ex_test ( sth ) :
ret = "b'"
i = 0
while i < len( sth ) :
if i+1 < len( sth ) :
next = sth[i+1]
else :
next = None
ret += i2s( sth[i], next )
i += 1
#
# end of while
#
ret += "'"
return ret
#
# end of repr_ex_test
#
#
##########################################################################
#
tmp=b'PK34'+b''*26+b'+(xcaxcc+xd1Pxf7Hxcd'+b'xc9'*2+b'Wbxcf/xcaIQTxd74PK12'+b''*6+b'1'+b''*9+b'x17'+b''*7+b'v'+b''*17+b'_'*2+b'main'+b'_'*2+b'.pyPK56'+b''*8+b'9'+b''*3+b'5'+b''*3
hexdump.hexdump( tmp )
print( repr_ex( tmp ) )
hexdump.hexdump( eval( repr_ex( tmp ) ) )
#
# other test case
#
tmp=b'abcabcx7fvvvf'
tmp=b'0aabcc'
tmp=b'x0057'
☆ i2s()
小侯让ChatGPT优化一下我写的i2s(),ChatGPT返回如下实现
def i2s_not_good ( i, next=None ) :
if chr(i) in 'rntabfv'"\' :
s = repr( chr(i) )[1:-1]
elif i >= 0x20 and i <= 0x7e :
s = chr(i)
elif i >= 0 and i < 8 :
if next is None or next < ord( b'0' ) or next > ord( b'7' ) :
s = r'%u' % i
else:
s = r'x%02x' % i
else :
s = r'x%02x' % i
return s
i2s_not_good()能用,不会致错,但就测试用例而言,有微妙的坑。留个小作业,不实际运行并观察结果的前提下,你能看出i2s_not_good()并不等价于i2s()吗,请指出坑点何在。我并未第一时间看出来坑点,是用测试用例发现的。
实际运行自然一目了然,这种13躲自个被窝里装去,千万别来,一旦被判定是这种13货,直接拉黑,不信邪的可以试试。
原文始发于微信公众号(青衣十三楼飞花堂):Python趣味题--求bytes的压缩显示(答案)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论