turns-00085.parquet:54272
21607a9128e5002428ffa330
turn 8/15gpt-4.1-mini-2025-04-14ChineseChina325 words
degenerate_repetitionAbsentFinal dense release
USER
一开始解码就不对, b'\x00\x01' -> 个 b'\x00\x02' -> 亻 b'\x00\x03' -> 箂 b'\x00\x04' -> 厉 应该对应的是 个 人 简 历
ASSISTANT
感谢补充说明!你指出你的映射表中:
```python
b'\x00\x01' -> 个
b'\x00\x02' -> 亻
b'\x00\x03' -> 箂
b'\x00\x04' -> 厉
```
但你期待的是:
```
b'\x00\x01' -> 个
b'\x00\x02' -> 人
b'\x00\x03' -> 简
b'\x00\x04' -> 历
```
也就是说,后几个字符的映射结果是错误的,实际上是“亻”“箂”这类拆字部件或奇怪字符,而非“人”“简”等完整汉字。
---
## 这说明你的 `add_mapping()` 里将 CID 到 Unicode 的映射字面值组装出错(构造了错误的字符串)。
---
### 重点看你 `add_mapping()` 这部分代码:
```python
if isinstance(char, PdfString):
char_bytes = char.to_bytes()
if sys.version_info < (3,):
char_bytes = (ord(c) for c in char_bytes)
c = ""
char_list = list(char_bytes)
for i in range(0, len(char_list), 2):
xh, xl = char_list[i], char_list[i + 1]
c += chr(xh * 256 + xl)
char = c
if offset > 0:
char = char[0:-1] + chr(ord(char[-1]) + offset)
else:
assert offset == 0
```
这里的核心问题是:
- 你用 `xh * 256 + xl` 把两个字节组合成一个数,`chr()`后直接以此为 Unicode 编码。
- 但其实 `char_bytes` 中的字节并不一定是高字节+低字节的UTF-16BE编码,可能是其它编码(或者就是 CID 字符码),转换成字符时会出错。
- 结果导致转换出像 “亻”(Unicode U+4EBB,0x4EBB=20187),“箂”(0x7B82=31682) 这样不是正确的字符。
---
### 你正确的期望是 “人”(U+4EBA)、 “简”(U+7B80)、 “历”(U+5386),这些汉字的 Unicode 码点而非拆字构件。
---
## 如何修复?
---
### 1. 你需要根据 CMap 规范正确解析 `char_bytes` 中的字节,通常 ToUnicode CMap 中的映射值是 UTF-16BE 编码的字符串,即每两个字节构成一个 Unicode 码点。
---
### 2. 改写 `add_mapping` 里转换 `char_bytes`为Unicode字符串的方式:
```python
if isinstance(char, PdfString):
char_bytes = char.to_bytes()
# char_bytes 是 UTF-16BE 编码字节流
# 针对 UTF-16BE 解析:
try:
char = char_bytes.decode('utf-16-be') # 这里改为直接标准解码
except Exception as e:
# 出错时打印日志,并尝试fallback
print(f"Warning: decode char_bytes failed: {e}")
# 这里临时尝试用latin1保证不丢失字节
char = char_bytes.decode('latin1')
if offset > 0:
# 如果有偏移,调整最后一个字符编码,示例暂略复杂,依据情况改写
last_char_code = ord(char[-1]) + offset
char = char[0:-1] + chr(last_char_code)
else:
assert offset == 0
```
---
### 3. 说明
- 使用 `utf-16-be` 解析 CMap 映射中的字符编码是标准做法,也符合 Adobe PDF CMap 规范。
- 解释:CMap 字符串内部字符是以 UTF-16BE 编码形式储存 Unicode 字符,例如 `<4EBA>` 其实是0x4E 0xBA,utf-16be 编码的“人”。
- 之前你是拼成一个整数后直接用 `chr()`,其结果有可能是码点范围正确,但不符合具体Unicode字符编码,导致多音间文字错误。
---
# 总结
修改你的 `add_mapping()` 中 `char` 解码为:
```python
if isinstance(char, PdfString):
char_bytes = char.to_bytes()
char = char_bytes.decode('utf-16-be')
if offset > 0:
last_char_code = ord(char[-1]) + offset
char = char[0:-1] + chr(last_char_code)
```
后期 `bytes_to_unicode` 映射的值将是正确的中文字符,`decode()` 返回的自然是正确的中文,`toUnicode()` 返回的就是正确汉字文本。
---
# 额外建议
- 如果你仍要处理偏移量 `offset` 较复杂,可以补充调整。
- 此外,确保 PDF 内容流经过了解压(`qpdf`)且用正确的字体关联,无外部缺失。
- 测试时打印映射表;确认`b'\x00\x02'`映射字符是 `"人"`。
---
希望这个解决方案帮到你!是你目前代码问题的关键点,修正这里后,你的中文脱敏文本映射应该会正确成汉字,从而后续的正则及替换才能正常工作。
如果需要可以帮你写一个精简的示例函数做UTF-16BE解码测试,欢迎继续交流。