EPUB 转 TXT:章节顺序和标题到底从哪来,以及记事本乱码/挤成一行怎么修

· 约 6 分钟 📖 EPUB 转 TXT

EPUB 转 TXT 看着是个”去掉标签”的活,实际结果差异很大:同一批书里有的转出来章节整整齐齐,有的顺序错乱、标题全丢、打开还是乱码。

差异不在工具的取舍,而在每本 EPUB 内部结构的规范程度。这篇把 EPUB 转 TXT 的解析链路拆开讲,你就能预判某本书会转成什么样,出问题时也知道该动哪个开关。

EPUB 就是一个 ZIP

.epub 改名成 .zip 解开,典型结构是这样:

book.epub
├── mimetype                    ← 固定内容 application/epub+zip
├── META-INF/
│   └── container.xml           ← 指向 OPF 的入口
└── OEBPS/
    ├── content.opf             ← 清单:metadata + manifest + spine
    ├── toc.ncx                 ← EPUB2 目录
    ├── nav.xhtml               ← EPUB3 目录
    ├── text/
    │   ├── part0001.xhtml      ← 正文(一章或多章)
    │   └── part0002.xhtml
    └── images/cover.jpg

解析顺序是固定的四步:

  1. META-INF/container.xml,拿到 OPF 的路径
  2. 解析 OPF 的三段:metadata(书名 / 作者 / 语言)、manifest(资源清单)、spine(阅读顺序)
  3. 定位目录文件:manifest 里 properties="nav" 的是 EPUB3 目录,media-type="application/x-dtbncx+xml" 的是 EPUB2 的 ncx
  4. 按 spine 顺序逐个读 XHTML,抽出文字

书名、作者来自 OPF 的 dc:title / dc:creator——这也是为什么有些书转出来的文件名和你在阅读器里看到的书名一致,而有些书是”未命名”:那本书的 OPF 里就没写。想修这个问题用 EPUB 元数据编辑 补上再转。

章节顺序:只认 spine

<spine> 是 OPF 里明确列出的翻页次序:

<spine toc="ncx">
  <itemref idref="cover"/>
  <itemref idref="chapter1"/>
  <itemref idref="chapter2"/>
  ...
</spine>

阅读器按它翻页,工具也按它遍历。按文件名排序会在三种常见情况下翻车

文件名形态字典序结果问题
part0012.htmltext00008.xhtml流水号与章节号无关顺序随机
ch1ch2ch10ch11ch1 → ch10 → ch11 → ch2第 10 章插到第 2 章前面
prefacech1appendix按字母排附录跑到正文前面

所以”章节顺序会不会乱”这个问题的答案是:只要这本 EPUB 的 spine 是对的,导出顺序就和阅读器完全一致;如果连阅读器里翻页顺序都是乱的,那是书本身坏了,转换救不回来。

章节标题:三级回退

标题的取值优先级:

① nav.xhtml(EPUB3)里指向该文件的链接文字
       ↓ 取不到
② toc.ncx(EPUB2)的 navPoint / text
       ↓ 取不到
③ 该章正文里第一个 <h1>~<h6> 的文字
       ↓ 取不到
④ 留空(该章无标题)

匹配方式是把目录里的 href 规范化成包内绝对路径后与 spine 文档比对,锚点(#part2)会被去掉、URL 编码会被解码——所以 ../text/ch1.xhtml#toptext/ch1.xhtml 能对上。

这里有一个必须知道的结构性限制

一个 XHTML 文件里塞了多章、目录靠 #anchor 分节的书,同一个文件只会取到第一个目录标题,几章正文也会被合并成一章。

这种书在预览里的表现是”章节数明显少于阅读器目录条数”——比如阅读器显示 120 章,工具只识别出 8 章。它不是 bug 而是 TXT 的表达能力问题:spine 里就只有 8 个文档,工具没有更可靠的依据在文件内部切章。真的需要按章切分时,可以先导出 TXT,再用 TXT 转 EPUB 按章节正则重新切一遍目录。

哪些页会被跳过

导出的 TXT 里不会出现这些内容:

被跳过的原因
nav.xhtml 目录页本身否则 TXT 开头会多出一份章节名清单
正文抽取后为空的文档纯封面页、纯图片页、占位页
非 XHTML 的 spine 项图片、SVG 等无文字内容
<script><style><head>代码和样式不是正文
<rt><rp>日文假名注音,否则会混进汉字之间

最后一条对日文书特别重要——不跳过 ruby 注音的话,“漢字”会被抽成”漢かん字じ”这种夹字结果。

正文换行怎么产生

抽取文字时,块级元素和 <br> 各产生一次换行

块级:p / div / h1~h6 / li / blockquote / section / article /
      tr / pre / hr / ul / ol / table / figure / figcaption /
      header / footer / aside / dd / dt / caption / main

然后做两步清理:

  1. 每行 trim,把不换行空格(&nbsp;)换成普通空格
  2. 去掉全部空行,再按”段落间空行”开关用 \n\n\n 重新连接

所以你在导出选项里控制的是段落密度,而不是原书的空行——原书里连续三个空行不会被照搬过来。表格会被拉平:每个 <tr> 一行、单元格文字挨在一起,结构信息丢失。

编码:EPUB 内部不一定是 UTF-8

规范要求 EPUB 用 UTF-8 或 UTF-16,但实际流通的书(尤其早期国产转换工具产出的)会出现 GBK 声明。工具的解码策略:

  1. 有 UTF-8 BOM → 去掉 BOM 按 UTF-8 解
  2. 否则扫描文件前 1KB,找 charset= / encoding= 声明
  3. 声明是 gbk / gb2312 → 用 GB18030 解(GB18030 是它们的超集,能覆盖更多生僻字)
  4. 声明的编码浏览器不支持 → 回退 UTF-8

所以输入侧的乱码基本能自愈。如果转出来的中文还是乱码,通常是这本 EPUB 的编码声明本身写错了(声明 UTF-8 实际是 GBK),这种只能用 Calibre 之类的工具先修再转。

输出侧:BOM 和 CRLF 分别治什么病

这两个开关经常被搞混:

症状病因开关
记事本里全文挤成一行换行符是 LF,老记事本只认 CRLF换行符 → CRLF
记事本里中文是乱码 / 锟斤拷无 BOM,被当成 ANSI(GBK) 打开UTF-8 BOM
脚本读文件首行匹配失败多了 BOM 那三个字节不要勾 BOM
手机阅读器显示正常但电脑异常手机端两种都认,问题只在电脑按电脑软件调

按目标设备的推荐配置:

使用场景BOM换行符
Windows 记事本、老 MP3 / 电子词典CRLF
手机阅读器(静读天下、多看等)不勾LF
macOS / VS Code / Sublime不勾LF
TTS 朗读软件视软件而定,先试不勾LF
喂脚本 / 入库 / Git 管理不勾LF

简繁转换与其它输出控制

  • 顶部书名 / 作者:在文首加 《书名》作者:XXX 两行,方便在一堆 TXT 里认书
  • 章节分隔:补齐标题(每章开头插入目录标题,正文首行已是该标题时不重复插入)/ 仅空行 / 不分隔
  • 段落间空行:段落之间留一行还是紧凑单行
  • 简繁转换:OpenCC 字典逐字转换,正文和标题同时生效

导出规模上的限制:单文件 100 MB,多本可一次拖入、打包 ZIP 下载;文件名取自书名并过滤掉 \ / : * ? " < > | 这些非法字符。

全程本地,与 TXT 转 EPUB 互逆

解压、解析、抽取、简繁转换、打包全部在浏览器里用 JavaScript 完成,断网也能用,文件不出本机

反方向的整理需求看这两篇:

❓ 常见问题

为什么不能按文件名排序,非要读 spine?

因为 EPUB 内部文件名和阅读顺序没有必然关系。常见的三种坏情况:(1) 转换工具生成的名字是 part0012.htmltext00008.xhtml 这类流水号,与章节序号不对应;(2) 名字是 ch1.xhtmlch2.xhtmlch10.xhtml,按字典序排会得到 ch1 → ch10 → ch11 → ch2 的错误顺序;(3) 前言、附录、版权页穿插在中间。唯一权威的阅读顺序是 OPF 里的 <spine>——它按 <itemref idref="..."> 明确列出翻页次序,阅读器也是照它翻页的。工具严格按 spine 遍历,所以导出的 TXT 顺序和你在阅读器里读到的完全一致。

章节标题为什么有的书有、有的书没有?

标题走三级回退:(1) 优先取 EPUB3 的 nav.xhtml 目录里对应该文件的链接文字;(2) 取不到就找 EPUB2 的 toc.ncxnavPoint 标签;(3) 都没有就取该章正文里的第一个 h1~h6 标题;(4) 还是没有就留空。所以标题全丢通常是三件事同时发生:这本书的 TOC 是用锚点(#anchor)指向同一个大文件的、正文用 <p class="title"> 这种样式冒充标题而没用 <h*> 标签、或者根本没有 TOC。前一种最常见——一个 XHTML 里塞了多章、靠锚点分节时,工具只能取到该文件的第一个目录标题,多章正文会被合并成一章

转出来在 Windows 记事本里全挤成一行,是不是文件坏了?

没坏,是换行符不匹配。TXT 默认用 LF(\n)换行,这是 Unix / macOS / 手机阅读器 / VS Code 的习惯;老版 Windows 记事本只认 CRLF(\r\n),遇到纯 LF 的文件就把全文当成一行。把导出选项的换行符切到 CRLF(Windows)重新下载即可。注意这和乱码是两个独立问题:挤成一行 → 换行符;汉字变成锟斤拷 → 缺 BOM,勾上 UTF-8 BOM。两个开关可以同时打开,专治老记事本。

勾了 UTF-8 BOM 会不会影响其它软件?

极少数会。BOM 是文件开头三个字节 EF BB BF,作用是告诉程序"我是 UTF-8"。Windows 记事本、部分老国产阅读器、Excel 导入需要它;但少数命令行工具、正则处理脚本会把 BOM 当成正文的第一个字符,导致首行匹配失败。取舍原则:文件主要给 Windows 记事本、老设备、TTS 软件用 → 勾上;要拿去喂脚本、diff、Git 或者导入数据库 → 不勾。手机阅读器(静读天下、多看等)和 macOS 两种都能正确识别。

我的 EPUB 是繁体的,转简体准确吗?

基于 OpenCC 字典逐字转换,对正文和章节标题同时生效,常见字形(電腦→电脑、髮→发)没问题。会出错的地方:(1) 一简对多繁的反向映射有歧义("发"对应"發 / 髮",简→繁时可能选错);(2) 人名地名、专有名词的港台写法不一定符合大陆习惯;(3) 原文简繁混排时会被统一成一种字形。建议流程:先在预览区抽查几段(工具会显示前 40 行预览),确认无误再下载;对翻译质量要求高的书,转换后仍需人工过一遍。

图片和表格会怎样?漫画能转吗?

图片一律丢弃——TXT 格式承载不了图像,插图、公式图片、漫画页转出来什么都不剩。表格会被拉平成一行行文字(单元格按块级元素换行),结构信息丢失。所以:文字小说、散文、论文、法条这类以文字为主的书转换效果最好;重排版的技术书(大量代码框、表格、图示)勉强可用但需要手工整理;漫画、图集、扫描版 PDF 转的 EPUB 完全不适合转 TXT。另外带 DRM 的商店购买书是加密包,无法解析,请先用合法手段解除 DRM。

📖 打开 EPUB 转 TXT 电子书提取纯文本·保留章节目录·书名作者·简繁转换·BOM/CRLF·多本批量·本地处理