总之我认为解密过程较为繁琐。
0x2 核心实现
激动人心的时刻到啦。让我们一步步编写。
首先在全局定义三个常量:
ZW_ONE = u"\u200b" # 用来翻译1
ZW_ZERO = u"\u200c" # 用来翻译0
ZW_SEP = u"\u200d" # 用来翻译字符之间的间隔
加密函数 str2zwstr(origin)
首先我们新建一个空数组,用来存储字符串每一项,并且遍历明文,使明文的每个字符先用ord()
转换成十进制数字,再用bin()
转换成二进制。再转换成字符串格式,最后去掉0b
前缀:
bin_text = []
for char in origin:
bin_text.append(str(bin(ord(char))).lstrip('0b'))
再创建一个空字符串,用来存储最终的结果:
final_str = ""
之后进行两次遍历,先浅层遍历bin_text
,然后为每一项深层遍历:
for item in bin_text: # 遍历大数组每一项
for binchar in item: # 遍历每一项中的0和1
final_str += ZW_ONE if binchar == "1" else ZW_ZERO # 把0、1分别翻译成两种零宽度字符串
final_str += ZW_SEP # 每一项(字符)结束后,插入一个分隔符号
final_str.rstrip(ZW_SEP) # 去掉
return final_str
最后返回final_str
即可。
整体代码:
def str2zwstr(origin):
bin_text = []
for char in origin:
bin_text.append(str(bin(ord(char))).lstrip('0b'))
final_str = ""
for item in bin_text:
for binchar in item:
final_str += ZW_ONE if binchar == "1" else ZW_ZERO
final_str += ZW_SEP
final_str.rstrip(ZW_SEP)
return final_stry
解密函数zwstr2str(enc_str)
首先我建议大家再看看基本思路中的流程图。解密不大相同。因为一开始我们要把翻译后的数据存储到第一个字符上,但是遇到分隔符后,我们又得新建一个字符,并把接下来的翻译后的数据存储到第二个字符串上,因此我们要编写一个函数apponlast(arr, sth)
,每次运行,都将sth拼接到arr的最后一项中,如果arr的项数为0,即新增一个元素。
我这里用的代码极为简洁:
def apponlast(arr, sth):
la = len(arr) # la 是 arr 的长度
if la: arr[la-1] += sth # 如果长度不为0,那么就把 arr 的最后一项与 sth 字符串拼接
else: arr.append(sth) # 如果数组里没有元素,新建一个元素
之后编写解密函数:
def zwstr2str(enc_str):
arr_oz = [] # 由0和1构成的字符串构成的数组
for char in enc_str: # 在密文里遍历
if char == ZW_ONE: apponlast(arr_oz, "1") # 如果是\200b,翻译成1
elif char == ZW_ZERO: apponlast(arr_oz, "0") # 如果是\200c,翻译成0
elif char == ZW_SEP: arr_oz.append("") # 如果是分隔符,把数组新建一项,重新开始循环
else: print("Input contains non-ZW string. Aborted."); getinput() # 如果密文中有非零宽字符,终止解密并回到程序主函数(我们一会要编写)
for idx in range(0, len(arr_oz)-1): # 遍历这个由0和1构成的字符串构成的数组
arr_oz[idx] = chr(int(arr_oz[idx], 2)) # 把每一项先转换为int(注意二进制参数),然后用chr转换为字符
return "".join(arr_oz) # 拼接
完善程序
接下来我们为程序添加一个主函数,并且加些花哨的功能。
if __name__ == '__main__':
pbanner()
getinput()
pbanner()
用来打印banner:
def pbanner():
banner = colored(f"""
______
/___ /\\ Zerowidth String Encoder | @TLHorse from 52pojie
// / / \\\\ Type in then ENTER. The encoded string
\\\\ / /__// will be copied & printed.
\/_____/ Commands | ::openweb:: ::banner:: ::quit:: ::switchmode::
""", 'yellow')
print(banner)
需要说明一下,上面的colored
函数需要依赖一个第三方库termcolor
,可以打印出彩色字符串。
我们在全局设置两个变量:
MODE_ENCODE = True # 用来记录模式是加密还是解密
LAST_RESULT = "" # 用来记录上次操作的结果
getinput
是一个递归,可以像命令行一样获取用户输入,代码比较复杂,功能很多,本来是有注释的,结果浏览器编辑的时候不小心给关了,没有恢复成功。大家自己摸索吧:
def getinput():
global MODE_ENCODE, LAST_RESULT
info = ""
if MODE_ENCODE: info = colored("ENCODE", 'red')
else: info = colored("DECODE", 'green')
input_str = input(f'[{info}] ')
if input_str == '::openweb::': os.system('open https://www.52pojie.cn') # 打开吾爱网页
elif input_str == '::banner::': pbanner() #打印banner
elif input_str == '::quit::': sys.exit(0) #退出程序
elif input_str == '::switchmode::': MODE_ENCODE = False if MODE_ENCODE else True #切换加解密
elif input_str == '::cp::': os.system(f'echo {LAST_RESULT} | pbcopy') #复制结果
if input_str.startswith("::") and input_str.endswith("::"): getinput() #检测是否为命令
out = str2zwstr(input_str) if MODE_ENCODE == True else zwstr2str(input_str)
print(colored(' >>> "', 'green')+ out + colored('"', 'green'))
LAST_RESULT = out
getinput()
别忘了import进类库:
import os, sys
from termcolor import colored
大功告成!
后记
首先,想说明一点,文中的结果复制功能是基于pbcopy命令的,这个只有Linux和Unix有,Windows没有。所以Windows小伙伴们记得使用pyperclip
库实现复制功能。
其次,我也不是程序员,所以代码的繁琐与不妥当之处欢迎跟帖指正。
最后,这篇文章很有可能会出续集哦!
所有代码长这样:
import os, sys
from termcolor import colored
ZW_ONE = u"\u200b"
ZW_ZERO = u"\u200c"
ZW_SEP = u"\u200d"
MODE_ENCODE = True
LAST_RESULT = ""
def pbanner():
banner = colored(f"""
______
/___ /\\ Zerowidth String Encoder | @TLHorse from 52pojie
// / / \\\\ Type in then ENTER. The encoded string will be printed.
\\\\ / /__// Commands | ::openweb:: ::banner:: ::quit:: ::switchmode::
\/_____/ ::cp::
""", 'yellow')
print(banner)
def apponlast(arr, sth):
la = len(arr)
if la: arr[la-1] += sth
else: arr.append(sth)
def str2zwstr(origin):
bin_text = []
for char in origin:
bin_text.append(str(bin(ord(char))).lstrip('0b'))
final_str = ""
for item in bin_text:
for binchar in item:
final_str += ZW_ONE if binchar == "1" else ZW_ZERO
final_str += ZW_SEP
final_str.rstrip(ZW_SEP)
return final_str
def zwstr2str(enc_str):
arr_oz = []
for char in enc_str:
if char == ZW_ONE: apponlast(arr_oz, "1")
elif char == ZW_ZERO: apponlast(arr_oz, "0")
elif char == ZW_SEP: arr_oz.append("")
else: print("Input contains non-ZW string. Aborted."); getinput()
for idx in range(0, len(arr_oz)-1):
arr_oz[idx] = chr(int(arr_oz[idx], 2))
return "".join(arr_oz)
def getinput():
global MODE_ENCODE, LAST_RESULT
info = ""
if MODE_ENCODE: info = colored("ENCODE", 'red')
else: info = colored("DECODE", 'green')
input_str = input(f'[{info}] ')
if input_str == '::openweb::': os.system('open https://www.52pojie.cn')
elif input_str == '::banner::': pbanner()
elif input_str == '::quit::': sys.exit(0)
elif input_str == '::switchmode::': MODE_ENCODE = False if MODE_ENCODE else True
elif input_str == '::cp::': os.system(f'echo {LAST_RESULT} | pbcopy')
if input_str.startswith("::") and input_str.endswith("::"): getinput()
out = str2zwstr(input_str) if MODE_ENCODE == True else zwstr2str(input_str)
print(colored(' >>> "', 'green')+ out + colored('"', 'green'))
LAST_RESULT = out
getinput()
if __name__ == '__main__':
pbanner()
getinput()
代码下载在这里:链接:https://share.weiyun.com/PyUOPC6F 密码:zsetlh