简介:这是一款为电子版小说与文本整理设计的轻量级工具,面向需要频繁合并TXT章节、转换编码或清洗文本的用户,适合小说编辑、电子书爱好者及办公人员使用。软件支持HTML转TXT、文件合并、TXT段落合并与分行、GB/GBK/Big5/Shift-JIS/Unicode多编码转换(适用于Win 2k/XP)、文本替换、HTML代码整理、文件切分、文本提取、正则表达式以及TCR批量压缩/解压,可单独或组合完成文本加工的多个环节。压缩包以rar发布,内共2个文件:1个exe程序可直接运行,1个htm文件作为说明文档,包体仅245KB,无需复杂安装即可使用。目前已有179人浏览学习。这款工具结合说明文档,能帮助用户快速理解各项功能操作逻辑,适合在小说章节合并、文档格式统一、乱码修复等场景中提高批量处理效率,节省大量重复劳动,尤其适合处理旧版电子书文本的编码转换与段落重排。
1. 先搞清楚 TextForever 文件合并和段落合并在解决什么
TextForever 的 TXT 文件合并和段落合并,其实是两种不同粒径的操作:文件合并是把多个 .txt 拼成一个 .txt,段落合并是把一个文件里被空行拆散的段落重新压成连续文本。很多人一上来就把它们当成同一个按钮,结果要么文件顺序乱掉,要么一段文字被硬拆成好几行。这个工具最适合处理三类人:写小说要整理章节的、做数据要汇总导出文本的、还有那些天天对着 shp 转 txt、RIS 文献导出、番茄小说导出的 TXT 做二次清洗的人。先理解这两层差别,后面才好谈做什么参数、怎么避坑。
2. 文件合并:把多个 TXT 变成一个大 TXT 的两种路径与取舍
2.1 先想清楚:文件合并要解决的是“顺序”和“边界”
TXT 文件合并不是把内容倒进同一个文件那么简单。合并之后你得知道每段内容是从哪来的,否则几十个文件拼在一起,后面检索、校对、按章节回退都无从下手。我一般会先把合并要解决的三个问题列清楚:来源顺序、文件边界、换行符与编码。
顺序问题最常见。Windows 资源管理器里2.txt和10.txt看起来是从小到大排的,很多工具按文件名排序时却会把10.txt排在2.txt前面,因为字符顺序里1小于2。如果你用批处理for %f in (*.txt)合并,这个坑更大,它按硬盘扫描顺序走,目录项创建顺序都可能影响结果。
边界问题很多人忽略。两个文件直接拼接,前一个文件末尾没有换行,后一个文件开头就粘上来了。所以合并时要给每个文件加分隔标记,常见做法是插入一个文件名注释行,或者至少补一个空行。TextForever 这类工具一般都能在“合并选项”里设置“文件之间插入分隔符”,我建议设成\n===== 文件名 =====\n,而不是只留一个空行,空行在后续段落处理里会被删掉,到时候就找不回边界了。
编码和换行符是黑匣子级别的问题。TXT 没有统一标准,有 UTF-8、UTF-8 BOM、ANSI/GBK、UTF-16。直接合并不同编码的文件,输出乱码几乎是必然。TextForever 的常见做法是统一按 UTF-8 输出,读取时自动识别或手动指定。但要注意,UTF-8 和 UTF-8 BOM 是两种文件,BOM 会跑到第一个文件开头,肉眼看不见却会让后面的解析出错。换行符也有 CRLF 和 LF 之分,Windows 记事本能忍,但给 RIS、GIS 工具用就很可能翻车。
2.2 TextForever 操作步骤:按文件列表顺序合并
以常见版本的 TextForever 为例,文件合并的主流程是这样:打开文件合并入口,按你想要的顺序把文件添加进列表,设置输出文件路径,选好编码和换行符,最后点执行。添加文件后,列表里通常有上移、下移按钮,或者支持拖拽排序,这一步一定不能省。我见过太多人用“全选添加”然后把顺序交给工具,合并完才发现章节乱序,只能重来。
为了让你可以复现,我用一段 Python 写出 TextForever 背后在做的核心逻辑:按给定文件顺序读取,中间插分隔行,最后写出。你不需要完整学会它,只看逻辑就能知道哪些参数在起作用。
from pathlib import Path files = ["01.txt", "02.txt", "03.txt"] # 按最终顺序列出来 out_path = Path("merged.txt") separator = "\n===== 分隔线 =====\n" with out_path.open("w", encoding="utf-8", newline="\n") as dst: for name in files: src = Path(name) # 读取时先按 utf-8-sig 解,失败再回退 gbk try: text = src.read_text(encoding="utf-8-sig") except UnicodeDecodeError: text = src.read_text(encoding="gbk", errors="replace") dst.write(separator) dst.write(text.rstrip("\r\n")) dst.write("\n") # 保证每个文件在输出里独占一个段落这里的utf-8-sig会去掉 UTF-8 BOM,避免 BOM 拼进正文;errors="replace"会把解析不了的字节替换成占位符,至少不会让脚本崩掉。newline="\n"是让输出统一用 LF,如果你后面要把结果交给 RIS 或 GIS 工具,LF 通常比 CRLF 更少出幺蛾子。参数上,最需要改的是separator:如果要给后续正则处理用,分隔行最好带一个固定前缀,比如=====,后面可以用^=+快速定位文件边界。
2.3 文件太多时:先导出文件列表,再按列表合并
如果只有三五个文件,手动拖拽排序没问题。但当你拿到一个目录里几百个 TXT,尤其是从 shp 转 txt、批量导出日志这种场景来的时候,手动添加不现实。常见做法是先在命令行导出一份按自然顺序排序的文件列表,再交给 TextForever 的“文件列表导入”功能去读。
ls -1v *.txt > filelist.txt-1表示每行一个文件名,-v表示版本号排序,能把1.txt、2.txt、10.txt按自然顺序排好,而不是按字符顺序把10.txt排在2.txt前面。Windows 上没有ls -v,我一般用 PowerShell:
Get-ChildItem -Name *.txt | Sort-Object { [int]([regex]::Match($_, '^(\d+)').Groups[1].Value) } | Out-File -Encoding utf8 filelist.txt这段脚本提取文件名开头的数字,按数值排序,把结果写进 filelist.txt。TextForever 读入这个文件列表后,会严格按照列表里的文件名顺序去读。注意一点:Get-ChildItem -Name只输出文件名,不输出路径,所以你要么先切到目标目录,要么在列表里写完整路径。文件列表本身也要放在待合并目录之外,否则它也可能被当成 TXT 合并进去。
提示:合并前先把目录备份一份,合并这个动作没有后悔药,顺序错了重来倒不难,难的是源文件已经被覆盖。
3. 段落合并:把散落段落压成连续文本的三条规则
3.1 合并段落的“单位”不是行,而是空行分隔出来的块
TXT 段落合并本质上是在做结构重排。一个段落可能占多行:有的编辑器自动换行,有的复制时会硬插入回车,有的导出文件把一句话断成几行。目标是把这些行重新拼成一个完整的段落,再把多个段落按你的需要合并成一段或保持一段一行。
先确认“段落”怎么定义。常见定义是:空行与空行之间的连续文本块,是一个段落。如果原文件里没有空行,只有硬换行,那要先做“段内换行识别”,也就是看行尾有没有句号、空格、引号等结束标记。TextForever 这类工具里,段落合并一般提供“按空行分割”“按行合并”“按正则分割”三个入口。新手最容易选错的是“按行合并”:它只是把相邻行用空格连起来,碰到两个独立段落没有空行分隔时,会把原本不该相连的两段也连到一起。
我给一个判断方法:先用编辑器把文件显示出来,看段落之间有没有空行。有空行,就选“按空行分割/合并”;没有空行但明显有逻辑段落,就先用正则给段落边界加空行,再做合并。常见做法是先插入两个换行符,把。\n替换成。\n\n,把章节标题也独立出来。
3.2 TextForever 做段落合并时的三个必调参数
打开 TextForever 的段落合并入口后,真正要调的参数其实只有三个:段落分隔符、段内换行处理、前后缀。下面是这三个参数在不同场景的推荐值:
| 场景 | 段落分隔符 | 段内换行处理 | 前后缀 |
|---|---|---|---|
| 小说正文合并 | 空行 | 空格 | 无 |
| 数据记录每行一条 | 不合并段内行 | 保留换行 | 每行加 ` |
| RIS 文献记录 | ER - | 保留换行 | 无 |
| GIS shp 转 txt 属性表 | 空行 | 分号 | 前后加引号 |
为什么“段内换行处理”这么重要?因为一段话在源文件里可能是这样:
北京到上海的高铁 每天发车密度很大 车站位于城市边缘直接合并成一行需要把行尾的换行替换成空格,得到“北京到上海的高铁 每天发车密度很大 车站位于城市边缘”。但如果这是一条 GIS 属性记录,每个字段本来该单独占一行,这时候不能把换行替换成空格,而应该保留,否则一个要素的多条属性会被挤进一个单元格。
TextForever 里这个选项通常会写成“段内换行替换为”,可填空格或空字符串。我一般填空格,因为中文文本里加空格不会粘连,英文文本更需要空格。如果填空字符串,中文没问题,英文会把两个单词拼成一个,这属于最常见的翻车现场。
3.3 最常见的误用:删掉空行不等于段落合并
很多人拿到乱排的 TXT,第一反应是写个正则把所有空行删掉。我见过不少从番茄小说导出的 TXT 就是被这么搞坏的:章节标题和正文之间的空行都删了,后面再想按章节切分,只能用“第一章”“第二章”这种关键词去猜边界,一旦章节标题格式不统一,就彻底找不回来。
正确的做法是先把空行当成结构保留,只把“段内硬换行”合掉,最后再去控制空行个数。举个例子,错误代码如下:
# 错误做法:删掉所有空行 for line in open("in.txt", encoding="utf-8"): if line.strip(): out.write(line)这段代码会让“第一段末尾”和“第二段开头”直接连在一起。要改成按段落合并,应该这样写:
from pathlib import Path text = Path("in.txt").read_text(encoding="utf-8-sig") # 空行作为段落边界切块 paras = [p.strip() for p in text.split("\n\n")] merged = "\n\n".join(paras) # 段落之间保留一个空行 Path("out.txt").write_text(merged, encoding="utf-8")注意这里split("\n\n")只能处理 LF 换行。如果原文件是 CRLF,读出来后\r\n\r\n不会被\n\n切到。解决方案是先做一次text = text.replace("\r\n", "\n"),把换行统一成 LF 再做段落切分。这一点 TextForever 图形界面可能已经帮你做了,但你自己写脚本时要记得,否则输出里的段落边界会变成半截空行,也就是每段末尾多一个回车符号,后面匹配正则时会出现一堆幽灵符号。
4. 从 shp 转 txt、RIS 文件合并到番茄小说导出:三个真实场景怎么组合使用
4.1 shp 转 txt 之后,为什么还要过一遍段落合并
GIS 里 shp 转 txt 已经很普遍,ArcGIS 的 Table To Text 工具一条要素记录导出来往往是一大块文本,字段之间用制表符或逗号分隔,换行符也不统一。有同学拿着导出的 TXT 直接做文件合并,结果一个要素拆成了好几行,后面做数据清洗每天都在对着黑匣子猜字段。
我一般建议的流程是:shp 转 txt 后,先做“记录边界还原”。每条要素记录的边界可以用空行或记录序号来判断,然后把一行一段的文本合并成一条。TextForever 的段落合并在这一步能帮上忙:把“段内换行替换为分隔符”设成|或;,再把多条记录合并成一个 TXT,这样后面用 Excel 分列或 pandas 读取时才能字段对得上。这里有个边界坑:shp 转 txt 常把长文本字段自动折行,如果直接把整条记录合并成一行,长文本里的空格会污染后续分词,所以分隔符建议用制表符\t而不是空格。
4.2 怎样将 2 个 RIS 文件合并为一个文件:不是普通 TXT 合并
RIS 文件合并是一个经常被搜到的问题。RIS 里每篇文献以ER -结尾,下一篇紧接着开始。直接把两个 RIS 文件拼起来,看起来没什么问题,但实际会遇到两个坑:第一个是第二个文件开头若带 UTF-8 BOM,BOM 会变成第一个字段的一部分,文献导入工具会报错;第二个是两个文件如果用了不同换行符,中间接缝处会出现半行记录。合并 RIS 文件应该照录结构,保留ER -行,只把两个文件之间的多余字节清干净。
常见做法是用代码做一次安全拼接,不改变文件内部结构:
from pathlib import Path ris_files = ["a.ris", "b.ris"] out = Path("merged.ris") with out.open("w", encoding="utf-8", newline="\n") as dst: for idx, name in enumerate(ris_files): text = Path(name).read_text(encoding="utf-8-sig") text = text.replace("\r\n", "\n") if idx > 0 and not text.startswith("TY -"): dst.write("\n") dst.write(text) if not text.endswith("\n"): dst.write("\n")utf-8-sig去掉每个文件开头的 BOM,idx > 0时如果第二个文件开头不是TY -,先补一个空行,避免第一条记录和上一条的ER -粘连。这里没有做真正的段落合并,而是做记录级合并,因为 RIS 的每行有自己的含义,不能把TI -和AU -并到一行里去。
TextForever 文件合并功能也能完成这个动作,但要在输出格式里选择“不插入分隔符”,并且把编码统一为 UTF-8。如果你用它的默认分隔符,会在两个 RIS 文件之间插入注释行,文献导入时非但不加分,反而会变成垃圾记录。
4.3 番茄小说导出 TXT 的段落清洗:先拆章节,再合并段落
很多人搜“番茄小说怎么下载成 txt”,最后拿到的还是几百 KB 的文本。这种文本有自己的脾气:章节标题和正文之间通常有空行,正文每行被强制切成固定宽度,还会带一些特殊空白符。如果直接用文件合并把十几章拼在一起,再一键段落合并,章节标题会被当成正文段落合并掉,后面切章节就麻烦了。
我的顺序是反过来的:先按章节标题拆块,再在每个块里做段落合并,最后再拼回一个完整 TXT。你可以先用正则找到第[一二三四五六七八九十百千0-9]+章这类标题,给它们统一加一行标记;然后对每一章内部做段内换行合并;最后再合并文件。TextForever 能处理的粒度是文件和段落,章节这种中间层需要你自己先切成单独文件,或者用“正则分割”功能把章节作为一个特殊段落边界处理。要注意章节标题格式千奇百怪,“第X章”后面可能没有换行,也可能有全角空格,正则里把这些变体都列出来,否则漏掉一章后面全乱。
提示:番茄小说导出的文本如果带水印,先做关键词过滤,再去做段落合并。水印混在正文里时,合并操作会把水印和正文拼成一句话,后面过滤正则更难写。
5. TXT 合并与段落合并避坑:5 条每次都会踩的问题
5.1 现象:合并后开头多了一个看不见的字符
现象是文件看起来没问题,第一行前面却好像有个问号或“锘”字,放到 RIS、GIS 工具里字段名对不上。
原因:源文件是 UTF-8 带 BOM,TextForever 读取时如果没有去 BOM,输出时把 BOM 字节当普通内容带进来了。
解决:读取时用utf-8-sig编码,或者在 TextForever 里把输出编码设为 UTF-8 无 BOM。如果是已经合并完的文件,用编辑器另存为 UTF-8 无 BOM 也可以。这个坑不是玄学,是每个合并工具都会遇到的默认行为,只是有的工具帮你处理了,有的没有。
5.2 现象:章节顺序变成 1、10、2、20
现象是文件列表里明明按 1、2、10、20 排好了,合并完却变成 1、10、2、20。
原因:合并工具按字符串字典序排序,"10"的第二个字符是0,ASCII 里比2小,所以排在2前面。
解决:合并前自己生成文件列表,不要依赖工具的全选添加。用我前面给的 PowerShell 数字排序脚本或 TextForever 的文件列表导入功能,先把顺序确定下来再合并。顺序这种事,合并完再想调整只能重新来,没有快捷键。
5.3 现象:段落合并后每段末尾残留半个空行
现象是把 CRLF 和 LF 混在一起的文件做段落合并后,正则匹配段落边界时总是多出\r,或者每段下面多一个看不见的换行符。
原因:文件从 Windows、Linux、Mac 三个平台凑到一起,换行符没统一。\r\n、\n、\r混合存在,按\n\n切块时切不干净。
解决:合并前先做一次换行符规范化,把所有\r\n和单独的\r都替换成\n。TextForever 如果有“统一换行符”选项就直接勾上;没有,就在段落合并前先跑一个批量替换脚本。别小看这个步骤,RIS 文件合并后出现半行记录,多半就是换行符在作怪。
5.4 现象:英文单词连成一片,中文句子丢标点
现象是段落合并后hello world变成helloworld,中文句子结尾和下一句开头粘在一起。
原因:把“段内换行替换为”配成了空字符串。中文里没有空格,空字符串看起来问题不大;英文里单词之间的空格被删了,语义直接崩。
解决:段内换行处理一律先用空格,尤其是源文件里有英文、数字、URL 的场景。想在中文里去掉多余空格,可以合并后再用正则把中文 中文之间的空格清掉,但英文两侧不要动。先保语义再优化,顺序不能反。
5.5 现象:大文件合并到一半卡死,输出只有前半部分
现象是合并几百 MB 的 TXT 时进度条不动,或者输出文件只有几 MB,内容明显断了。
原因:很多文本批处理工具一次把整个文件读进内存,文件大于内存或文件数过多时就会假死。段落合并还会做正则替换,正则回溯一卡就是几十秒。
解决:把大文件拆成小批次,比如一次合并 20 个文件,输出成一个中间文件,再做第二轮合并。如果单个文件本身就几百 MB,先用工具按行数切分,或者直接用命令行工具做流式拼接,不要强行塞给图形界面。TextForever 处理这种场景时,我一般只让它做“小文件合并”,大文件走脚本。
6. 最后再教你一手:用「合并前先统计」验证合并结果是否可用
我在合并一堆 TXT 前,一定会先跑一段统计脚本,给每个文件留下一个行数、段落数、字符数的底账。合并后再跑一次统计,拿合并后的总数和源文件总和去对。对得上,说明至少没有丢内容;对不上,说明合并工具在某个文件上漏了行或改了换行。
from pathlib import Path for p in sorted(Path("inputs").glob("*.txt")): raw = p.read_bytes() try: text = raw.decode("utf-8-sig") except UnicodeDecodeError: text = raw.decode("gbk", errors="replace") text = text.replace("\r\n", "\n") paras = sum(1 for block in text.split("\n\n") if block.strip()) print(p.name, "lines=", text.count("\n") + 1, "chars=", len(text), "paras=", paras)这里统计的是:文件总行数、总字符数、按空行切出来的段落数。合并前把每个文件的数字抄到一张 Excel 里,合并后再看总数。如果合并在文件之间插入了分隔行,总数会比源文件总和多出分隔行那一部分,你要能算清这个差值,而不是直接要求完全相等。
我自己的习惯是,合并前先看三个东西:有没有 BOM、有没有 CRLF 混用、文件名有没有“10 比 2 先排”的风险。这三样都正常,才点执行。有一回我图快,跳过了统计,直接把两百个 TXT 合并完,结果中间丢了三十个文件,事后只能靠源文件备份重新来。那次之后,合并前留底账就成了我的默认动作,过程很笨,但能救命。
希望你也能在动手前先把账算清楚。希望帮到你。
本文还有配套的精品资源,点击获取