使用PyPDF2修改PDF文本时英文拆分、阿拉伯语识别异常问题求助
问题根因&解决方案
问题1:英文单词拆分显示异常
PDF规范中TJ运算符本身支持将文本拆分为多个带字符间距调整的片段存储,你当前的逐行直接替换逻辑没有处理拆分的文本片段,会出现占位符/单词被拆分到不同片段无法匹配、替换后结构错乱的问题。
问题2:阿拉伯语替换失效
PDF内容流中的字符串编码不是默认使用UTF-8,而是和对应位置绑定的字体编码相关,阿拉伯语常用的CP1256、Identity-H等编码直接用UTF-8解码会被转为八进制转义字符,自然无法和你写的UTF-8阿拉伯语字符串匹配。
修改后的可运行代码
import os import argparse import re from PyPDF2 import PdfFileReader, PdfFileWriter from PyPDF2.generic import DecodedStreamObject, EncodedStreamObject, NameObject # 匹配TJ操作的正则 TJ_PATTERN = re.compile(r'\[(.*?)\]\s*TJ', re.DOTALL) # 匹配TJ数组内的文本片段+位移的正则 SEGMENT_PATTERN = re.compile(r'\((.*?)\)\s*([-+]?\d*\.?\d+)?') def merge_tj_text(tj_content): """把TJ数组里的所有文本片段拼接成完整字符串""" segments = SEGMENT_PATTERN.findall(tj_content) full_text = '' for seg, _ in segments: # 处理转义字符 seg = seg.replace(r'\(', '(').replace(r'\)', ')').replace(r'\\', '\\') full_text += seg return full_text, segments def rebuild_tj_content(segments, replacements): """替换文本后重新生成TJ内容""" new_segs = [] for seg, offset in segments: original_seg = seg.replace(r'\(', '(').replace(r'\)', ')').replace(r'\\', '\\') replaced_seg = original_seg for k, v in replacements.items(): replaced_seg = replaced_seg.replace(k, v) # 转义特殊字符 replaced_seg = replaced_seg.replace('\\', r'\\').replace('(', r'\(').replace(')', r'\)') if offset: new_segs.append(f'({replaced_seg}){offset}') else: new_segs.append(f'({replaced_seg})') return f'[{" ".join(new_segs)}]TJ' def replace_text(content, replacements = dict(), encoding='cp1256'): # 先处理编码适配,阿拉伯语常用cp1256,可根据实际字体编码调整 content = content.decode(encoding, errors='replace') # 处理所有TJ操作 def replace_tj(match): tj_content = match.group(1) full_text, segments = merge_tj_text(tj_content) # 替换文本后重构TJ结构 return rebuild_tj_content(segments, replacements) result = TJ_PATTERN.sub(replace_tj, content) return result.encode(encoding) def process_data(obj, replacements): data = obj.getData() replaced_data = replace_text(data, replacements) if obj.decodedSelf is not None: obj.decodedSelf.setData(replaced_data) else: obj.setData(replaced_data) if __name__ == "__main__": ap = argparse.ArgumentParser() ap.add_argument("-i", "--input", required=True, help="path to PDF document") args = vars(ap.parse_args()) in_file = args["input"] filename_base = in_file.replace(os.path.splitext(in_file)[1], "") # 阿拉伯语替换规则 replacements = {'اسم': 'يارا'} pdf = PdfFileReader(in_file) writer = PdfFileWriter() for page_number in range(pdf.getNumPages()): page = pdf.getPage(page_number) contents = page.getContents() if isinstance(contents, (DecodedStreamObject, EncodedStreamObject)): process_data(contents, replacements) elif len(contents) > 0: for obj in contents: if isinstance(obj, (DecodedStreamObject, EncodedStreamObject)): streamObj = obj.getObject() process_data(streamObj, replacements) page[NameObject("/Contents")] = contents.decodedSelf writer.addPage(page) with open(f"{filename_base}.result.pdf", 'wb') as out_file: writer.write(out_file)
额外注意事项
- 如果你的PDF阿拉伯语字体用的不是CP1256编码,可以把
replace_text函数里的encoding参数改成对应编码,比如utf-8、iso-8859-6等 - 若处理排版复杂的PDF,推荐使用
PyMuPDF(fitz)库完成文本替换,操作逻辑更简单,稳定性远高于直接修改PyPDF2的原始内容流 - 阿拉伯语为右到左书写的RTL语言,替换后如果出现文字顺序颠倒,需要调整文本的写入顺序适配PDF的RTL渲染规则
内容的提问来源于stack exchange,提问作者Sara Kat
相关产品推荐
相关产品推荐

