☰
genoffice pdf2docx 日语黄金回归语料(ja golden cases)深度解析:kana/kanji 混排、半角片假名与纵向排版安全降级
2026/9/28 3:32:49 网站建设 项目流程
  • 人工智能
  • AI 应用
  • 桌面应用
  • AI Agent
  • MCP 服务
  • AI 技能

【免费下载链接】genoffice

Free, open-source AI Office suite: Docs, Sheets, Slides, PDF, Markdown and HTML editors with a built-in AI agent, plus a `genoffice` CLI and agent skill so Claude Code, Codex and Cursor can create and edit real .docx/.xlsx/.pptx files locally. Bring your own key. macOS, Windows & Linux.

项目地址:https://gitcode.com/gh_mirrors/ge/genoffice
点击查看免费下载

本指南围绕开源 AI 办公套件 genoffice 的 pdf2docx 包中 日语黄金回归语料说明 展开,剖析 PDF→DOCX 转换管线在日语场景下的三大核心保障:kana/kanji 无空格混排、半角片假名识别、以及纵向排版(tategaki)页面降级为整页位图而非输出乱序文本的兜底策略。读完你既能理解黄金语料库的组织方式与断言约定,也能从 script.ts、words.ts、extract/index.ts 等源码中掌握其底层实现原理与验证方法。

语料文档说了什么:ja 用例的验收红线

packages/pdf2docx/tests/golden/ja/README.md篇幅极短,却定义了日语 PDF 转 Word 的“验收红线”,共三条目标覆盖(Target coverage):

  1. kana/kanji 混排且不加空格(kana/kanji mixing without spaces):日文假名与汉字之间不允许机器插入任何空格,转换结果必须是连续的原样文本;
  2. 半角片假名(halfwidth katakana):アイウエオ这类半角片假名必须被正确归类并原样保留;
  3. ruby 尺寸的小字号 run(ruby-sized small runs,P1 阶段按“普通小字号 run”处理):注音假名(furigana)这类紧贴汉字的小号文本,P1 只需作为普通小字号文本 run 保留,不要求识别为真正的 ruby 结构。

此外还有一条全局红线:纵向排版(tategaki,日语竖排)页面必须降级为整页位图(full-page bitmap),绝不允许输出乱序/打乱的文本(never emit scrambled text)。

这份文档属于 黄金回归语料库总说明(golden regression corpus)的一个语言子集。总说明定义了语料的组织方式:golden/下按语言分目录,en/(拉丁文本:词间距阈值、连字、对齐)、zh/(简体中文:不加空格、eastAsia 字体槽、中英混排)、ja/(日语)、ko/(韩语:保留真实词间空格)、ar/(阿拉伯语:P1 降级位图,P2 翻转为真实 RTL 输出)。

每个用例的数据结构:PDF 与 expected.json 配对

按总说明约定,每个黄金用例都是一对文件:

  • <name>.pdf—— 输入文档(体积小、可安全再分发);
  • <name>.expected.json—— 断言快照,至少包含四类校验:
    • 段落文本按序出现(paragraph texts in order);
    • 每段的 align/indent(对齐方式与缩进);
    • 图片数量(image count);
    • 预期 warnings(预期产生的告警列表,例如纵向排版页应产生 "vertical or rotated text, exported as full-page image" 之类的告警)。

这种“输入 PDF + 结构化断言 JSON”的设计使回归语料既可用于持续集成,也能在每次修复上游回归后增量提交样本(约定命名issue-<n>-*,如 pdf2docx 上游的 #103 丢/增空格、#73 RTL 反转问题,见 golden/README.md)。

注意:P1 阶段采用“随测随生成”的 fixture(on-the-fly fixtures),提交的二进制样本随每次修复的回归逐步增长;遍历这些目录的 runner 会随首个提交样本一起落地。

日语核心保障一:kana/kanji 混排永不插入空格

日文句子(如こんにちは世界。日本語のテストです。)是假名与汉字连续书写的,字符之间本来就没有空格。PDF 转 DOCX 的最大风险是分析器根据字符间距推断“词间距”时误插空格,把完整日文打散。

底层依据:Unicode 脚本分类

这一保障的根基在 script.ts。它把 Unicode 码点映射为 8 类脚本:latin、cjk、hangul、kana、thai、arabic、hebrew、common。日语相关的关键区间:

  • kana(平假名+片假名):0x3040–0x30FF(hiragana + katakana)、0x31F0–0x31FF(katakana 语音扩展);
  • 半角片假名:0xFF66–0xFF9F(halfwidth katakana)——这正是 ja 语料中“halfwidth katakana”覆盖点对应的分类区间;
  • cjk(汉字/表意文字):0x2E80–0x2FDF(部首)、0x3000–0x303F(CJK 符号与全角标点。、「」)、0x3400–0x4DBF、0x4E00–0x9FFF、兼容表意文字0xF900–0xFAFF、竖排形式0xFE30–0xFE4F、全角 ASCII 与标点0xFF00–0xFF65、扩展 B..G0x20000–0x3134F等。

硬规则:no-space scripts

words.ts 中的shouldInsertSpace在推断词间距前先执行硬规则(HARD RULE):

// HARD RULE: never machine-insert spaces next to CJK/kana/Thai characters if (isNoSpaceScript(prev.script) || isNoSpaceScript(cur.script)) return false

script.ts 中的isNoSpaceScript判定cjk、kana、thai为禁插空格脚本,而hangul 被刻意排除——韩语书写真实词间空格,必须走拉丁词距规则,这正是 ko 语料与 ja 语料分治的原因:

export function isNoSpaceScript(script: UnicodeScript): boolean { return script === 'cjk' || script === 'kana' || script === 'thai' }

对应的单元测试在 script.test.ts 中明确断言“no-space scripts 是 cjk/kana/thai,NOT hangul”,并验证あ、ア、半角ア均分类为kana,。、全角A分类为cjk。

端到端验证

tests/integration.test.ts 中有专门用例ja: kana + kanji text survives intact:用buildCjkPdf生成包含こんにちは世界。日本語のテストです。的 PDF,经convertPdfToDocx转换后断言段落文本完整包含原句——一字不多、一字不少、无插入空格。同文件中zh/en mixed用例还验证了中英混排会被拆成cjk / latin / cjk三个 run,而文本内容不被改写。

日语核心保障二:半角片假名正确归类与保留

ja 语料明确覆盖 halfwidth katakana。半角片假名位于0xFF66–0xFF9F,在 script.ts 中被专门映射为kana(而非cjk或common)。这一分类的意义:

  • 它属于 no-space 脚本,相邻半角假名不会被插入空格;
  • 它属于东亚字体槽脚本,重建时落入w:eastAsia字体槽(见下文),保证 Word 中用日文字体正确渲染而非落到西文槽位显示异常。

script.test.ts 的第 23 行直接验证:expect(scriptOf(cp('ア'))).toBe('kana') // halfwidth katakana。

日语核心保障三:ruby 尺寸小字号 run(P1 按普通小 run 处理)

日文排版常见“注音假名”(furigana/ruby):在汉字上方或下方排布的小字号假名。ja 语料规定 P1 阶段这些 ruby 尺寸的小 run不需要被识别为 ruby 对象,只要作为普通小字号文本 run 原样保留即可(P1: plain small run)。

源码中对“微型文本”有一套专门保护逻辑,见 analyze/spacing.ts 的isMicroTextBlock:当某文本块所有行的所有 span 字号都小于MICRO_TEXT_MAX_PT = 2.5pt时,它被判定为 micro text——不参与段落间距链(spacingBefore 推导),因为“给不可见/微缩文本链上真实间距会把可见内容挤下页”。同理,extract/index.ts 中的“无墨验证”(invisible-glyph verification,P20)专门针对低于页面字号中位数 70% 的疑似小号字符做渲染验证,防止把 Word 隐藏格式标记误当正文。这些机制共同保证小号 ruby run 在重建后既不被丢弃、也不会扰乱版式。

全局红线:纵向排版(tategaki)页面降级为整页位图

这是 ja 语料最重要的安全承诺:竖排页面绝不允许输出乱序文本。竖排文本在 PDF 中通常以接近 ±90° 的字符角度呈现,若按横排逻辑重建,行序、字序都会被打乱,产生“scrambled text”。genoffice 的策略是:检测到竖排/旋转文本即降级该页为整页位图。

检测机制:旋转字符比率

在 extract/index.ts 的assessQuality中:

/** |angle| above this (radians, ~15°) counts a char as rotated/vertical */ const ANGLED_CHAR_RAD = 0.26 /** share of rotated chars that triggers the vertical-text fallback */ const ANGLED_RATIO = 0.3

流程为:先做 ToUnicode 质量门(坏码点比率 >BAD_UNICODE_RATIO = 0.15或触发 mojibake 检测即判bad-tounicode),然后统计|angle| > 0.26 弧度(约 15°)的字符占比,超过 30% 即返回vertical-text降级判定:

const angled = textChars.filter((c) => Math.abs(c.angle) > ANGLED_CHAR_RAD).length if (angled / textChars.length > ANGLED_RATIO) { return { degraded: true, reason: 'vertical-text', scanned: false, badUnicodeRatio } }

降级执行:渲染整页位图

在 pipeline.ts 中,vertical-text的告警标签被描述为“vertical or rotated text”,且降级页面会清空 blocks/sections/shapes 并调用renderPageByIndexPng渲染整页 PNG:

const DEGRADED_LABEL: Record<string, string> = { ... 'vertical-text': 'vertical or rotated text', ... }

渲染分辨率由renderScale控制(默认 2 px/pt,见 pipeline.ts 的ConvertOptions)。此外还有布局置信度兜底:analyze/confidence.ts定义PAGE_CONFIDENCE_MIN = 0.5,置信度低于 0.5 的页面同样降级为位图(reasonlow-confidence),与vertical-text共同构成“忠实于原页而非乱码”的保底策略。

特例:cell-data 模式(xlsx 导出)

xlsx 导出器 的cellData模式对竖排页采取不同策略:它保留水平字符(旋转的地图/平面图标签被丢弃,因为它们无法成为单元格),而不是整页降级;只有整页完全旋转的页面才落入 content-lost 兜底。这一区别说明 ja 语料的“整页位图降级”是针对 DOCX 流式重建的默认行为,而表格数据导出另有取舍。

日语渲染的配套设施:eastAsia 字体槽与 CJK 合成度量

降级之外的正常页面,日语文本要真正在 Word 中显示正确,还需要两套设施:

1.w:eastAsia字体槽映射。在 rebuild/index.ts 中:

// CJK-family scripts fill the w:eastAsia slot (docx-engine Run.font); // everything else declares only the Latin slots (fontAscii) if (isEastAsianScript(span.script)) run.font = span.fontFamily else run.fontAscii = span.fontFamily

script.ts 的isEastAsianScript将cjk、kana、hangul归为东亚脚本——日文(汉字+假名)因此总是写入w:eastAsia,Word 会选用日文字体渲染,而不是用西文字体槽产生字形替换问题。

2. CJK 合成宽度度量。rebuild/fit.ts 的 P31 A 规则指出:所有 CJK 输出字体中,表意文字、假名、谚文都以恰好 1 em 渲染,全角标点亦然,因此它们的宽度根本不需要字体文件参与度量——cjkSyntheticWidthPt直接按“全角码点记 1 em、其余记 0.5 em”合成宽度:

const cjkSyntheticWidthPt = (text: string, sizePt: number): number => { let ems = 0 for (const ch of text) ems += isFullwidthCode(ch.codePointAt(0)!) ? 1 : 0.5 return ems * sizePt }

这也规避了映射字体不可解析的问题,是日语页面能脱离具体字体文件完成精确重建的前提。

日语 fixture 如何生成:基于 PDFium 的 CJK 测试基建

黄金语料和集成测试依赖一套“现场生成”的 CJK PDF 基建,位于 tests/helpers/fixtures.ts:

  • pdf-lib 自带字体无 CJK 覆盖,因此CJK fixture 改用 PDFium 自身生成:通过_FPDFText_LoadFont嵌入系统 CJK 字体后逐行写入文本对象;
  • 系统字体路径按平台探测(macOSArial Unicode.ttf、Windowsarialuni.ttf、LinuxNotoSansCJK-Regular.ttc),找不到合适系统字体时测试自动跳过(describe.skipIf(!hasCjkFont)),这也是 ar 语料迟迟不提交二进制样本的原因(golden/ar/README.md 明确说明:本地 Arial Unicode 不可再分发,需等 Amiri 这类 SIL OFL 自由字体加入工具链);
  • 日语示例buildCjkPdf(pdfium, cjkFontBytes(), [{ text: 'こんにちは世界。日本語のテストです。', x: 72, y: 700 }])直接在测试中构造输入,端到端断言输出。

这套基建意味着:即使没有提交二进制 PDF,ja 语料的核心行为也已由集成测试持续守护;而golden/ja/目录则用于沉淀需要快照回归的固定样本(段落顺序、对齐、缩进、图片数、warnings 的逐字段断言)。

如何运行与扩展 ja 语料

  • 运行测试:在仓库根目录或packages/pdf2docx下执行 vitest 即可跑通全部相关用例,例如npx vitest run tests/script.test.ts tests/integration.test.ts;依赖系统 CJK 字体的用例在无字体环境会自动跳过;
  • 新增回归样本:遵循总说明约定——上游 pdf2docx issue 的负面案例移植到对应语言目录并命名为issue-<n>-*;PDF 要么用tests/helpers/fixtures.ts现场生成,要么来自自由许可证;提交的样本越小越好(redistribution-safe);
  • 断言内容:新样本的<name>.expected.json必须覆盖段落文本顺序、每段对齐/缩进、图片数量、预期 warnings 四类字段,确保一次回归能被精确捕获;
  • 验证竖排降级:任何纵向排版样本的 expected.json 都应断言该页产生vertical-text相关 warning 且整页以图片形式输出,防止未来某个“聪明”的重建逻辑开始输出乱序文本。

小结

ja 黄金语料文档虽仅五行,却是整个 pdf2docx 日语策略的浓缩契约:no-space 硬规则(script.ts 的脚本分类 + words.ts 的isNoSpaceScript)、半角片假名归类、小字号 ruby run 的保守保留(spacing.ts 的 micro text 保护),以及竖排页面整页位图降级(extract/index.ts 的 30% 旋转字符门 + pipeline.ts 的vertical-text降级渲染)。配套的w:eastAsia字体槽映射与 CJK 合成宽度度量,则保证了正常日语页面在 Word 中能正确呈现。对任何需要处理日文 PDF 的转换工具而言,这套“能则保留文本、不能则安全降级为图、绝不出乱码”的验收哲学,比单纯追求转换率更值得借鉴。

  • 人工智能
  • AI 应用
  • 桌面应用
  • AI Agent
  • MCP 服务
  • AI 技能

【免费下载链接】genoffice

Free, open-source AI Office suite: Docs, Sheets, Slides, PDF, Markdown and HTML editors with a built-in AI agent, plus a `genoffice` CLI and agent skill so Claude Code, Codex and Cursor can create and edit real .docx/.xlsx/.pptx files locally. Bring your own key. macOS, Windows & Linux.

项目地址:https://gitcode.com/gh_mirrors/ge/genoffice
点击查看免费下载

相关推荐

上一篇:txgbe-driver实战案例:企业级10GbE网络部署经验分享
下一篇:终极指南:uos-dovecot-exporter 如何彻底解决邮件服务器监控难题

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询