Files
kefu/wechat_rpa/tmp/repair_encoding.py
2026-08-18 17:25:22 +08:00

90 lines
2.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""修复 wechat_bot.py 的字节级损坏。
损坏形态:个别字节被就地替换成 0x3f('?'),字节长度不变,行结构完好。
因此可以用 git HEAD 版本做参照:把损坏行里的 0x3f 当通配符,在 HEAD 里找
长度相同、其余字节全部一致的唯一候选行来还原。
默认只报告不写入;加 --write 才真正落盘。
"""
import subprocess
import sys
def load_head() -> bytes:
return subprocess.run(
["git", "show", "HEAD:wechat_rpa/wechat_bot.py"],
capture_output=True,
check=True,
cwd="..",
).stdout
def is_valid(line: bytes) -> bool:
try:
line.decode("utf-8")
return True
except UnicodeDecodeError:
return False
def candidates(broken: bytes, pool: dict) -> list:
"""在同长度的候选里找出「除 0x3f 位置外完全一致」的行。"""
found = []
for other in pool.get(len(broken), ()): # 长度相同才可能是同一行
if all(
b == o or b == 0x3F
for b, o in zip(broken, other)
):
found.append(other)
return found
def main():
write = "--write" in sys.argv
current = open("wechat_bot.py", "rb").read()
head = load_head()
cur_lines = current.split(b"\n")
head_lines = head.split(b"\n")
pool = {}
for line in head_lines:
pool.setdefault(len(line), []).append(line)
broken_idx = [i for i, line in enumerate(cur_lines) if not is_valid(line)]
print(f"总行数 {len(cur_lines)},损坏行 {len(broken_idx)}")
repaired = list(cur_lines)
fixed = unresolved = ambiguous = 0
unresolved_lines = []
for i in broken_idx:
found = set(candidates(cur_lines[i], pool))
if len(found) == 1:
repaired[i] = found.pop()
fixed += 1
elif len(found) > 1:
ambiguous += 1
unresolved_lines.append((i, cur_lines[i], len(found)))
else:
unresolved += 1
unresolved_lines.append((i, cur_lines[i], 0))
print(f"可唯一还原 {fixed},歧义 {ambiguous}HEAD 里找不到 {unresolved}")
if unresolved_lines:
print("\n需要人工确认的行(最多列 40 条):")
for i, line, n in unresolved_lines[:40]:
print(f" 第 {i + 1} 行 候选={n}: {line.decode('utf-8', 'replace')!r}")
if not write:
print("\n(只报告,未写入。加 --write 才落盘)")
return
out = b"\n".join(repaired)
open("wechat_bot.py", "wb").write(out)
print(f"\n已写回 {len(out)} 字节")
if __name__ == "__main__":
main()