指南

如何从泰语 PDF 和扫描件中提取文字

从泰语 PDF 复制文字时为什么会出现错乱的声调符号、乱码和连成一片的短语,以及泰语 OCR 如何把页面还原成文字、标题和表格。

· 阅读约 2 分钟

从泰语 PDF 中取出文字,有两种途径。带文本层的文件可以直接复制。扫描文件则要靠 OCR 读取:OCR 把页面当作图像来看,再把上面的文字写出来。

问题在于,泰语 PDF 的文本层常常存着错乱的文字,即使页面打印出来完全正常。声调符号顺序错位,旧字体提取出来是拉丁字母乱码,整个短语变成一段不断开的字符串,泰文数字和阿拉伯数字挤在同一行。下文逐一列出每种问题及其产生的字符串,然后说明什么时候该用 OCR,以及文档 OCR 读取一张真实泰语发票后返回什么。

泰语 PDF 的两种类型#

从文字处理软件、会计系统或浏览器导出的 PDF 带有文本层。页面上的字形由字体绘制,背后的字符存储在文件里。全选后复制,总能得到一些内容。

来自扫描仪、手机相机或传真网关的 PDF 是装图像的容器,页面就是像素。在识别程序把像素转换成字符之前,全选选不到任何内容,搜索也搜不到。

两项快速检查就能区分它们。在文件里搜索一个页面上看得见的词,如果它明明在页面上却搜不到,这一页就是图像。拖动鼠标选中一行,如果选区把整页框成一个矩形,或者什么都选不中,这一页也是图像。许多真实的泰语文档是混合的:打字填写的表格是文本层,盖章、签名或批注的部分则是叠在上面的图像。

泰语 PDF 的文本层为什么会出错#

英文提取常见的问题只有一种:栏与栏之间的空格丢失。泰语提取有四种,每一种产生的文字看上去都说得过去,直到泰语读者或数据库真正用到它。

声调符号和元音符号顺序错乱#

泰语音节会在辅音的上方和下方叠加符号。กุ้ง(虾)这个词按 Unicode 顺序是四个码位,正确的文本层也按这个顺序存储。逐个排布字形的 PDF 生成程序可能把声调符号存在元音之前,因为声调符号先画出来。有些生成程序把这些符号当作定位好的图形绘制,文件里根本没有对应的字符。

一个词,四个码位,三种存储顺序
กุ้ง   as written

U+0E01 ก   base consonant
U+0E38  ุ  vowel below
U+0E49  ้  tone mark above
U+0E07 ง   final consonant

ก ้ ุ ง     the same four, as one PDF stores them
ก ง         the same word, marks placed as art

两种情况提取出来的字符串都显示得几乎正确,却什么都匹配不上。搜索 กุ้ง 会失败,存储这个字符串的数据库无法用它做关联,下游翻译也会把它读成另一个词。页面本身从头到尾看起来都没有问题。

旧字体提取出来是拉丁字母乱码#

在 Unicode 普及之前,泰语文档使用 TIS-620 编码,以及带有私有字形映射的字体排版。这些文件至今仍在流通,政府表格、合同和地契都还在用它们重新印制。用这类文件生成的 PDF 有文本层,但其中的字节只有认识该代码页的程序才能读成泰文。通用提取工具会按 Latin-1 读取,得到下面这些字符。

旧字体在页面上和文件中的样子
กรุงเทพ        on the page
A1 C3 D8 A7 E0 B7 BE   in the file (TIS-620)
¡Ãا෾         after extraction

这种乱码是确定性的,TIS-620 的情况可以用对照表映射回来。字体私有映射则没有对照表可用。这时,看得见的页面是文字唯一可靠的副本,而这正是扫描件的定义。

词与词之间没有空格#

泰语的词连在一起写,空格用来分隔短语和分句。一张发票的正确文本层会把 ใบแจ้งหนี้เลขที่ 作为一个整体返回。任何按空格切分、用 \b 匹配词边界或按固定宽度换行的工具,处理的都是它看不进内部的短语。文字本身是对的,处理它的工具出了问题。

两套数字同处一行#

泰语文档的日期、数量和地址用泰文数字(๑ ๒ ๓),金额用阿拉伯数字,两者出现在同一张表格里,有时还在同一个单元格里。日期写作 ๑๕ กรกฎาคม ๒๕๖๙,采用佛历纪年。数量 ๔ 紧挨着金额 3,000.00。其中还夹杂着拉丁字母,从 INV-2569-0107 这样的发票号到产品名称都有。如果提取时把数字统一转换,或者假设每个字段只有一种文字,数值就会在不知不觉中被改掉。

什么时候该对泰语 PDF 使用 OCR#

文件情况处理方式
有文本层,提取出的文字正确直接使用文本层,并保留生成程序存储的结构
有文本层,但符号顺序错乱或缺失把页面当作图像,用 OCR 读取
有文本层,但旧字体提取出拉丁字母乱码把页面当作图像,用 OCR 读取
扫描或拍照的页面OCR
打字表格上叠有盖章或手写内容整页 OCR,再与文本层对照

OCR 像人一样从像素读取页面,不关心文件如何存储字符。因此,除第一行外,上表每一种情况都适合用 OCR。对于混合页面,它也是唯一能读出盖章、签名和手写部分的工具。

文本层干净时不该用 OCR,那样要花一次视觉识别的成本,去取回文件里本来就有的文字。先做那两项检查。

文档 OCR 读取泰语页面后返回什么#

字符识别返回的是一串字符,文档 OCR 返回的是整个页面。Paxa OCR Lite 按阅读顺序读取整页,可以返回保留了标题和表格的 Markdown,也可以返回带类型的块(标题、段落、列表、表格、图片),供代码处理。下面几行是一张泰语示例发票已存档读取结果的开头部分,未经编辑。

一张泰语发票的读取结果,开头几行
# บริษัท ศตวรรษการค้า จำกัด (สำนักงานใหญ่)
เลขประจำตัวผู้เสียภาษีอากร 0 1055 64078 12 7

# ใบแจ้งหนี้
เลขที่ INV-2569-0107
วันที่ ๑๕ กรกฎาคม ๒๕๖๙

| ลำดับ | รายละเอียด | จำนวน | หน่วยละ | จำนวนเงิน |
| ๑ | ค่าบริการดูแลระบบรายเดือน กรกฎาคม ๒๕๖๙ | ๑ | 18,000.00 | 18,000.00 |
| ๒ | ค่าพื้นที่จัดเก็บข้อมูลส่วนเกิน | ๔ | 750.00 | 3,000.00 |

( สามหมื่นหกพันสามร้อยแปดสิบบาทถ้วน )

这段摘录里有三处,正是文本层提取容易出错的地方。明细行的序号和数量用泰文数字,金额用阿拉伯数字,两者都按印刷的数字原样返回。日期采用佛历,按印刷原样返回,由应用程序自行换算。大写金额 สามหมื่นหกพันสามร้อยแปดสิบบาทถ้วน 是一整串没有空格的泰文,返回时也是一行。

把 output 设为 structured,同一页会以带类型的块返回。公司名称是一级标题块,每一行标签是段落块,明细则是一个表格块,每一行都是由单元格字符串组成的数组。代码从标签后的文字读出发票号,从这个块的各行读出明细,不需要为每家供应商准备模板。

表格按表格返回。按像素条带扫过页面的识别程序,会把这五列压成每行一条文字,分不清哪个数字是单价。完整的读取结果及其所用的示例页面,见发票页面。

如何检查泰语 OCR 结果#

读取结果忠实于原文,而文档本身也可能有错。下面这些检查能在数值进入系统之前,发现泰语商务文档中的大部分问题。

  • 泰国纳税人识别号为 13 位。去掉空格后数一数,0 1055 64078 12 7 符合要求。
  • 每行金额等于数量乘以单价,小计、7%的增值税和总计也要对得上。读取结果自相矛盾,说明有某个数字读错了。
  • 大于 2500 的年份是佛历年份,存为日期前先减去 543。๒๕๖๙ 即 2026 年。
  • 表格行数应与页面上的明细条数一致。在内容密集的发票上,行被合并是最常见的表格错误。
  • 泰文数字和阿拉伯数字都要能解析为数值。用对照表转换,手工转换会引入错误。
  • 大写金额应与总计一致。这个字段本来就是人们为了发现这类错误而写上去的。

说明

税务发票是法律文件,其栏目由泰国《税收法典》规定,普通发票则是商业单据。税务发票页面列出了这些法定栏目,审计时核对的正是它们。

泰语 OCR 的价格和支持的文件#

按页计费。每页 6.5 积分,即每千页 $6.50,与页面上的文字多少无关。新账户自带 100 免费积分,可读取 15 页。

一次请求可接收不超过 10 MB、不超过 50 页的 PDF、PNG、JPEG 或 WebP 文件。一张图片算一页。扣费前会先从文件中读取页数,需要密码的 PDF 会在扣除任何积分之前被拒绝。

应付账款团队如何让每张供应商发票都走这套流程,见发票处理页面。

现在就从泰语 PDF 中提取文字#

  • 先做那两项检查。如果文本层读出来是对的,就直接用它。
  • 把出错的页面或扫描页拖进控制台,查看返回的 Markdown。第一页不需要写任何代码。
  • 接下来由人或语言模型阅读结果时,选 markdown;由代码处理时,选 structured。
  • 请求格式见 OCR 指南,所有字段和错误见 API 参考。
  • 用上面的检查清单核对前一百份文档,保留真正发现过问题的检查项。
  • 泰语 OCR 页面收录了一份完整文档的实录读取结果,以及十二种文档类型的示例读取结果。

继续阅读

更多指南