You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PdfStream字节数组含括号与浮点值导致替换失效求助

解决PDF Stream文本替换失效的问题

为啥直接用String.replace没用?

PDF里的文本不是像普通文档那样存成连续字符串的,比如你要替换的DCC ID: XXX-X,在PDF的内容流里是拆成了带位置偏移的片段——就像你贴的[(TEST ID:)0.5 ( X)-15.3 (X)-15.2...]TJ这种格式:每个括号里是一小段文本,后面跟着的数字是字符间距或位置偏移。直接用String.replace找完整的目标字符串,自然匹配不到这些被拆碎的片段。

解决思路

得先把分散的文本片段拼接成完整字符串,替换完成后再重新拆回带偏移的结构,具体步骤:

  • 解析PDF内容流,定位TJ文本绘制指令,分离出其中的文本片段和偏移值
  • 拼接所有文本片段得到完整字符串,执行替换操作
  • 将替换后的字符串按原片段长度拆分,保留原偏移值(若替换前后长度差异大,需额外调整偏移保证排版正常)

实际代码示例(基于iText 7)

import com.itextpdf.kernel.pdf.PdfStream;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IRenderListener;
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
import com.itextpdf.kernel.pdf.canvas.parser.data.ImageRenderInfo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class PdfTextReplacer {
    public static byte[] replaceStreamText(PdfStream stream, String oldText, String newText) throws IOException {
        // 存储TJ指令的所有元素:文本片段+偏移数字
        List<Object> tjElements = new ArrayList<>();
        StringBuilder fullText = new StringBuilder();

        // 解析内容流,提取TJ操作的内容
        PdfCanvasProcessor processor = new PdfCanvasProcessor(new IRenderListener() {
            @Override
            public void beginTextBlock() {}

            @Override
            public void endTextBlock() {}

            @Override
            public void renderImage(ImageRenderInfo renderInfo) {}

            @Override
            public void renderText(TextRenderInfo renderInfo) {
                // 获取TJ指令对应的原始操作数
                List<Object> originalTjParts = renderInfo.getTJOperands();
                for (Object part : originalTjParts) {
                    tjElements.add(part);
                    if (part instanceof String) {
                        fullText.append((String) part);
                    }
                }
            }
        });

        processor.processContent(stream.getBytes(), stream.getResources());

        // 替换完整文本
        String updatedFullText = fullText.toString().replace(oldText, newText);

        // 重构TJ指令内容,保留原偏移值
        List<Object> newTjElements = new ArrayList<>();
        int textCursor = 0;
        for (Object elem : tjElements) {
            if (elem instanceof String) {
                int partLength = ((String) elem).length();
                // 按原片段长度截取新文本
                String newTextPart = updatedFullText.substring(textCursor, Math.min(textCursor + partLength, updatedFullText.length()));
                newTjElements.add(newTextPart);
                textCursor += partLength;
            } else {
                // 偏移数字直接复用
                newTjElements.add(elem);
            }
        }

        // 将重构后的TJ内容转为字节数组
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write("[".getBytes());
        for (int i = 0; i < newTjElements.size(); i++) {
            Object currentElem = newTjElements.get(i);
            if (currentElem instanceof String) {
                // 转义PDF字符串中的特殊字符
                String escapedStr = ((String) currentElem)
                        .replace("\\", "\\\\")
                        .replace("(", "\\(")
                        .replace(")", "\\)");
                outputStream.write(("(" + escapedStr + ")").getBytes());
            } else {
                outputStream.write(currentElem.toString().getBytes());
            }
            if (i != newTjElements.size() - 1) {
                outputStream.write(" ".getBytes());
            }
        }
        outputStream.write("] TJ".getBytes());

        return outputStream.toByteArray();
    }
}

注意事项

  • 示例基于iText 7,若使用旧版本iText,API需对应调整
  • 如果替换前后文本长度差异较大,直接保留原偏移会导致排版错乱,此时需要结合PDF字体信息重新计算偏移值
  • 实际场景中可能存在多个TJ指令,需遍历整个文本块的所有指令进行处理

内容的提问来源于stack exchange,提问作者sandeep sangole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 03:25:46