使用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
相关产品推荐
相关产品推荐

