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

使用PdfSharp提取PDF文本遇编码异常,求解决方案

解决PdfSharp提取PDF文本出现特殊控制字符的问题

问题原因

你遇到的\0\u0019这类字符属于Unicode控制字符,出现的核心原因有两个:

  • PDF内容流中混入了非文本的操作指令字节,被误当作文本内容读取
  • 目标PDF使用了自定义字体编码,PdfSharp默认的CString.Value没有通过字体的ToUnicode映射表转换字符,导致原始编码字节被直接解析成无效Unicode

修复方案

1. 过滤不可打印控制字符

先对提取到的文本做过滤,保留可打印字符(包括中文、英文、数字、常用符号以及换行/制表符等有用格式字符)。

2. 解析字体的ToUnicode映射

PDF的文本显示依赖字体的编码映射,必须获取当前文本操作对应的字体,通过其ToUnicodeCMap把原始编码字节转换成正确的Unicode字符。

修改后的完整代码

using PdfSharp.Pdf.Content;
using PdfSharp.Pdf.Content.Objects;
using PdfSharp.Pdf.IO;
using PdfSharp.Pdf.Advanced;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Job_Ingestor
{
    public static class PdfSharpExtensions
    {
        public static string ExtractTextByRow(PdfDocument doc, int pageIndex = 0)
        {
            PdfPage page = doc.Pages[pageIndex];
            var extractedText = page.ExtractText();
            return string.Join("", extractedText);
        }

        public static IEnumerable<string> ExtractText(this PdfPage page)
        {
            var content = ContentReader.ReadContent(page);
            var fontState = new FontState { CurrentPage = page };
            return content.ExtractText(fontState);
        }

        private static IEnumerable<string> ExtractText(this CObject cObject, FontState fontState)
        {
            if (cObject is COperator cOperator)
            {
                // 跟踪当前使用的字体(Tf操作符:设置字体和字号)
                if (cOperator.OpCode.Name == OpCodeName.Tf.ToString())
                {
                    if (cOperator.Operands[0] is CName fontName)
                    {
                        var font = fontState.CurrentPage.Document.Internals.GetFont(fontName.Value);
                        fontState.CurrentFont = font;
                    }
                }
                // 处理文本绘制操作
                else if (cOperator.OpCode.Name == OpCodeName.Tj.ToString() || 
                         cOperator.OpCode.Name == OpCodeName.TJ.ToString())
                {
                    foreach (var operand in cOperator.Operands)
                    {
                        foreach (var text in operand.ExtractText(fontState))
                        {
                            yield return FilterPrintableChars(text);
                        }
                    }
                }
            }
            else if (cObject is CSequence cSequence)
            {
                foreach (var element in cSequence)
                {
                    foreach (var text in element.ExtractText(fontState))
                    {
                        yield return text;
                    }
                }
            }
            else if (cObject is CString cString)
            {
                if (fontState.CurrentFont != null)
                {
                    // 通过字体的ToUnicode映射转换原始字节到Unicode
                    var unicodeText = fontState.CurrentFont.ToUnicode(cString.Value);
                    yield return unicodeText;
                }
                else
                {
                    // 无字体映射时直接返回原始值(仍需过滤)
                    yield return cString.Value;
                }
            }
        }

        /// <summary>
        /// 过滤不可打印的控制字符,保留常用可打印字符和格式字符
        /// </summary>
        private static string FilterPrintableChars(string input)
        {
            // 保留ASCII可打印字符(32-126)、中文、常用符号,以及换行(\n)、制表符(\t)
            return Regex.Replace(input, @"[^\u0020-\u007E\u4E00-\u9FFF\n\t]", "");
        }

        /// <summary>
        /// 跟踪当前PDF内容流中的字体状态
        /// </summary>
        private class FontState
        {
            public PdfPage CurrentPage { get; set; }
            public PdfFont CurrentFont { get; set; }
        }
    }
}

关键修改说明

  • 新增FontState类跟踪当前文本操作使用的字体,解决PDF内容流中字体切换的问题
  • 处理Tf操作符获取当前字体,通过PdfFont.ToUnicode()方法完成编码映射转换
  • 加入FilterPrintableChars方法过滤无效控制字符,只保留可打印内容
  • 优化字符串拼接逻辑,用string.Join替代循环累加,提升性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:35:11