
简介这是一份面向电子书整理、文本批量处理与编码转换场景的轻量工具资源适合经常阅读 TXT 小说、制作仿真电子书或管理 TCR 格式文档的读者与编辑也适合需要在多个文档间完成合并、拆分、替换等预处理工作的办公用户。它集成文件合并、TXT 段落合并与分行、HTML 转 TXT、HTML 代码整理、文本替换、文件切分、文本提取、正则表达式匹配以及 TCR 批量压缩/解压等功能并支持 GB/GBK/Big5/Shift-JIS/Unicode 等常见编码在 Windows 2K/XP 环境下相互转换。压缩包内共 2 个文件包含一个可直接运行的 exe 主程序和一个 htm 帮助说明文档整体仅 245KB无需安装即可使用。目前已有 178 人浏览学习借助该工具可针对大量 TXT 或 HTML 文件执行自动化批量操作利用正则表达式精准提取关键章节也能统一处理不同编码的文档减少重复劳动。整体短小实用适合各类文本处理需求的初学者快速上手。1. TextForever 是什么这个老牌文本工具凭什么解决 TXT 合并的麻烦你手上有一套分卷下载的 TXT 小说或者从后台导出的几十个 CSV 转存文本想拼成一个干净的大文件打开 TextForever 之前得先想明白一件事文件合并不是「把文件凑在一起」而是「把编码、换行、段落规则统一成一个标准」。TextForever 是个老牌的 Windows 文本整理工具开源免费最常见的用途就是 TXT 文件合并和段落合并——前者解决几十个文件拼成一个后者解决一个文件里几百行短行拼成通顺段落。它界面朴素功能却比记事本和 Excel 扎实得多处理这类脏活很少掉链子。适合分卷小说整理、语料清洗、报告文本汇总这类需求也适合不想为一个合并动作专门去写脚本的人。2. 把多个 TXT 合并成一个文件文件合并的操作路径与编码处理文件合并看起来是「全选 → 合成」两步实际上涉及文件读取顺序、编码识别、输出编码三个环节。TextForever 的合并原理并不神秘把每个文件按行读进来转成内部统一的 Unicode 表示再按你指定的目标编码写出去。我一般会把合并拆成三个动作来理解——读入、编码归一、写出。读入阶段的坑在于有的文件是 GBK 有的是 UTF-8不归一直接拼出来的就是一半中文一半乱码归一阶段决定输出编码是 UTF-8 还是 ANSI写出阶段才决定要不要在文件之间插空行、要不要保留原文件末尾的换行。这三个环节里顺序搞错、编码选错、换行没处理是绝大多数合并翻车的根源。2.1 添加文件、排序与合并按钮背后的处理顺序TextForever 合并操作的常见路径是把文件逐个添加到左侧列表确认顺序点合并选择输出文件名。界面不复杂真正影响结果的不是按钮本身而是文件列表里的顺序。合并是严格按照列表顺序逐文件追加的不是按照文件在磁盘上的创建时间或名称来排。你看到列表里第 10 卷排在第 2 卷前面合出来的文件就会从第 1 卷跳到第 10 卷再跳回第 2 卷整本书章节直接错乱。这里有个 Windows 用户很容易忽视的差异资源管理器用的是自然排序同一个目录里「第 2 章.txt」和「第 10 章.txt」资源管理器会把 2 排在 10 前面但很多文本工具的文件列表用的是字典序也就是逐字符比较结果第 10 章反而排到第 2 章前面。下表是这个差异的直观对比文件名资源管理器自然排序字典序排序第1章.txt11第2章.txt210第10章.txt32第11章.txt43所以合并分卷文件之前我要做的第一件事不是点合并而是核对列表里的实际顺序。TextForever 这类工具一般支持在列表内上下移动条目顺序不对就直接拖拽调整如果文件数量太大更省事的做法是先把文件名统一补零成 01、02、10 这种格式字典序和自然序就一致了。合并的内部动作还有一个容易忽略的细节最后一个文件末尾如果没有换行符下一个文件的第一行就会直接贴上来形成「上一章结尾和下一章标题挤在同一行」的怪象。TextForever 一般有控制选项我习惯勾选「文件间插入换行」。这相当于在每个文件交界处显式补一个换行符从根上避免粘连。合并完成后先别急着关直接看合并文件开头、第一个文件交界处和文件末尾三个位置再决定要不要保留原文件。2.2 编码识别与统一合并前先解决 GBK 和 UTF-8 打架的问题TXT 文件最常见的编码有四种ANSI在中文 Windows 下即 GBK、UTF-8 无 BOM、UTF-8 带 BOM、UTF-16少见但存在。「带 BOM」的意思是文件开头有三个字节 EF BB BF用来标记自己是 UTF-8记事本打开看不到但把这个文件和别的文件拼在一起时三个字节会原样保留下来合并结果的开头或交界处就会多出一个不可见字符严重时显示成「锟斤拷」或空方框。TextForever 处理编码有两种常见策略自动识别和手动指定。自动识别的原理是先看文件头有没有 BOM 标记有就直接判定没 BOM 就尝试按 UTF-8 解码解不开就退回到 GBK。这个策略对大多数文件是准的但碰到短文件、全是字母数字的文件、或者恰好是 GBK 编码的 UTF-8 兼容文本时识别结果就成了玄学。我合并之前不会把识别交给黑匣子而是先跑一个检查脚本把这个目录下每个 TXT 的编码和末尾换行情况列出来import glob from pathlib import Path def sniff_head(path, n4096): with open(path, rb) as f: return f.read(n) def guess_encoding(raw): if raw.startswith(b\xef\xbb\xbf): return utf-8-sig if raw.startswith(b\xff\xfe): return utf-16-le if raw.startswith(b\xfe\xff): return utf-16-be try: raw.decode(utf-8) return utf-8 except UnicodeDecodeError: return gbk for p in glob.glob(*.txt): raw sniff_head(p) enc guess_encoding(raw) has_eol raw.rstrip().endswith(b\n) print(f{Path(p).name}: {enc}, 末尾换行{has_eol})这个脚本的逻辑分两层先看 BOM 魔数BOM 是文件自己声明的身份比解码推断更可靠再看能否严格按 UTF-8 解码能解就是 UTF-8不能解就按 GBK 处理。参数里 n4096 表示只看文件头 4KB对编码判断足够速度也快末尾换行检查用于决定合并时要不要勾「文件间插入换行」。跑完你会发现一个目录里的文件编码经常是混的——这种情况就别在合并选项里纠结了先把所有文件统一转成 UTF-8 无 BOM再谈合并。顺带说一句输出编码的选择我永远优先选 UTF-8。GBK 是老编码跨平台时经常出乱码而 UTF-8 在文本编辑器、Python、手机阅读器里都是默认兼容的。如果合并后的文件要给别人在 Windows 记事本里打开选 UTF-8 带 BOM 会更稳但代价是每个文件交界处的 BOM 要额外处理。二选一的话UTF-8 无 BOM 加文件间换行是最稳的组合。2.3 分卷小说与 CSV 批量合并两种常见场景的参数设置分卷小说是 TextForever 最典型的应用场景。很多人从番茄小说这类阅读器导出分卷文本或者整理《剑来》这种几百章的超长连载一套下来几十个文件。这类文件的特征每个分卷 1-2MB内部章节标题格式统一正文段落有缩进但卷与卷之间可能存在重复的封面信息或分卷标号。合并参数我会这样设文件间插入一个空行输出编码 UTF-8 无 BOM文件交界处不保留原分卷的空白页。插入空行的目的是让卷与卷之间有一个明显的分隔边界后续按章节切分时不容易把上一卷的尾巴和下一卷的头部粘在一起。合并完还有一个常见问题分卷文件里往往自带「本卷完」「下一卷预告」这类内容如果这些杂质在卷首或卷尾合并后就会混进正文。这类行靠合并工具本身删不干净需要在合并前先用「行处理」功能把包含特定关键词的行挑出来或者合并后用搜索定位再手动清理。我的习惯是合并不动内容只动结构杂质清理放到合并之后的统一处理阶段。另一个高频场景是把多个 CSV 格式的文件合并在一起。CSV 本质是纯文本合并动作本身没问题麻烦在表头和编码。大多数业务系统导出的 CSV 是 GBK 编码用记事本打开正常但和 UTF-8 文件合并后必乱。另一个坑是表头多个 CSV 每个文件都带一行列名合并完整个文件每隔几百行就重复出现一次表头直接没法导入数据库。正确做法是保留第一个文件的表头跳过其余文件的表头行。TextForever 没有专门的 CSV 模式但可以先做一步行处理把「不需要表头」的文件逐一删掉第一行再执行合并。文件多的时候我倾向直接全量合并后用脚本清理重复表头这一步也没什么难度import csv, glob header None with open(merged.csv, w, encodingutf-8-sig, newline) as out: w csv.writer(out) for name in glob.glob(part_*.csv): with open(name, encodinggbk, errorsreplace) as f: rows csv.reader(f) for i, row in enumerate(rows): if i 0: if header is None: header row w.writerow(row) continue w.writerow(row)这段逻辑的核心是一个状态变量 header第一个文件的第一行被当作真正的表头写入之后所有文件的第一行统统跳过其余行原样写入。参数里 encodinggbk 是承接这批文件的导出编码如果文件是 UTF-8 就改成 utf-8-sigerrorsreplace 是遇到无法解码的坏字节时用替换符顶替避免单个坏字符导致整个合并中断。注意输出用的是 utf-8-sig 而不是 utf-8这是为了让 Excel 直接双击打开时能正确识别 UTF-8不会出现中文列名乱码。3. TXT 段落合并把「一行一短句」恢复成通顺的段落文本段落合并是 TextForever 另一个核心功能解决的是完全不同的痛点单个文件里内容没乱但排版乱了——每行只有几个字一段话被硬拆成十几行或者整篇文本堆成一大坨没有任何分段。这个需求主要来自三种文本网页复制出来的文章、OCR 识别结果、字幕或聊天记录导出。它们的共同点是「行」和「段落」不是一回事需要按语义把行重新拼起来。TextForever 的段落合并做的就是这件事把连续若干行按规则拼成一个段落同时保留真正的段落边界。3.1 段落是怎么定义的空行、缩进、硬回车与逻辑段要理解段落合并先分清两种换行。第一种是「硬回车」它是真正的段落边界一个段落结束、另一个段落开始的地方第二种是「软换行」它只是排版层面的断行同一句话因为行宽被拆成了两行语义上还是一个段落。段落合并的核心动作就是把软换行替换成空格或不加任何字符而把硬回车原样保留。问题来了软件怎么知道一个换行是硬的还是软的TextForever 这类工具的判断依据通常是行特征。中文文本里一个段落内的续行往往以两个全角空格开头而段落的首行才会有缩进段落结尾的一行通常以句号、问号、感叹号、引号收尾章节标题行则既没有行首缩进也没有句尾标点需要单独保护。这几个特征组合起来基本能覆盖绝大多数网页复制文本的识别需求。行的特征与实际含义的对应关系大致如下行的特征大概率是段落合并时的建议以全角空格或制表符开头段内续行直接并入当前段以句号、问号、叹号、引号结尾段落结束行合并时在此换段行首有「第…章/节/卷/回」章节标题合并前单独加空行保护整行为空段落间分隔保留作为段边界只有几个字且无标点续行或标题结合上下文判断实际操作里没有哪个规则是百分百准的所以我一般把段落合并拆成两步先做「空行规整」再做「行合并」。空行规整的意思是连续多个空行压缩成一个让段落边界变得唯一且可预测行合并则把所有非空行按上述特征拼起来。这样即使个别行的判断错了也不会把两段内容彻底粘死边界还在手动修复的成本很低。3.2 段落合并的四个参数分隔符、空行策略、行宽与处理范围段落合并界面的参数不算多但每个参数都对结果有直接影响。我把最常调的四个列出来按影响程度排序。参数可选值中文场景建议英文场景建议合并分隔符无 / 半角空格 / 全角空格 / 制表符无或全角空格半角空格空行策略保留空行 / 删除空行 / 空行作为段边界保留空行保留空行行宽折行不折行 / 按字数折行60-80 字折行80 字符折行处理范围选中区域 / 整个文件先做选区测试先做选区测试合并分隔符是第一个要定的参数。中文文本合并时行与行之间加不加空格要看原文本如果原文是网页复制出来的行尾断在「的」「了」这种虚词后面不加空格直接拼接最自然如果原文是英文或中英混排行尾可能直接断开一个单词这时必须用半角空格分隔否则单字会被硬拼在一起。全角空格和制表符一般用于特殊排版需求比如保留原文的行首缩进结构日常处理基本用不到。空行策略关系到的不是行而是段。TextForever 的常见选项是「保留空行」「删除空行」「把空行当作段落边界」。网页复制文本最常见的形态是段落之间有空行段内行之间没有空行这时候选「保留空行」空行就是天然的段落边界段内行会被自动合并。反过来如果文本里空行很多且无规律选「删除空行」再做行合并可能把两段言论粘成一段所以删除空行这个选项我基本不用。行宽折行是在段落合并完成后对长段落做二次切割切到指定宽度好让手机阅读器或后续处理工具能正常显示。这个参数容易让人误解它不是把「长行」变「短行」而是把合并出来的超长段落按字数重新切行。中文场景建议 60-80 字这个宽度在手机和 PC 上显示都比较舒适如果文本后续要进脚本处理建议不折行让脚本自己处理换行。处理范围决定了这次段落合并对哪些行生效。我强烈建议第一次操作时只选一小段文本做测试确认合并效果符合预期再扩大到整个文件。段落合并是不可逆的——它把多行并成一行行结构被破坏没有后悔药。就算 TextForever 界面里可能有撤销几十万行的文件撤销一次也够你等的。测试选区这个习惯能省掉大量返工时间。3.3 从网页复制的文章乱成一坨段落合并的实战顺序网页复制过来的文本有个典型形态每行十几个字行尾有时有标点有时没有行首有时有缩进有时没有段落之间有零到多个空行。这种文本直接点段落合并出来的结果往往是一半段落正确、一半段落粘死原因不是工具不行而是处理顺序不对。正确的顺序是这样的第一步把文本粘贴进 TextForever先关掉编辑区的自动换行显示。这一步很关键因为启用自动换行时你看到的「行」是显示层折行不是真实行段落合并按真实行操作两者不一致会让你误判。第二步压缩空行。把连续多个空行统一成最多一个空行这一步用替换功能即可把「两个以上换行」替换成「一个换行」。经过这一步段落边界就变成唯一的有且仅有一个空行的地方就是段与段的交界。第三步去掉每行行首的全角空格和制表符。网页复制文本的行首经常带着缩进保留缩进去做合并缩进字符会被拼到段落中间变成段落里突兀的空格。用正则替换匹配行首的空白字符替换为空即可。第四步执行段落合并分隔符选「无」空行策略选「保留空行」。第五步检查合并结果。重点看每段末尾是不是以句号、引号收尾段首是不是顶格。如果个别段落仍然粘在一起直接手动在正确位置插入一个空行再重新跑一次段落合并。这五步的顺序有讲究。先合并再去空行是错的段落合并已经把行拼起来了空行虽然还在但行首缩进已经不在行首而在段中替换就失效了先合并再检查缩进也是错的全角空格混在段落文字中间肉眼极难发现。顺序对这个流程能在几分钟内把一篇几十页的网页文章还原成干净的分段文本。OCR 场景同理只是 OCR 文本往往连空行都没有整块文字堆在一起需要先手动在语义断点处插入空行再走合并流程。4. 文本合并避坑乱码、错序、大文件卡死与章名被吞合并工具本身不难难的是合并前的脏数据和合并后的验收。这一章集中写我踩过、也看别人反复踩的四类坑。每个都按「现象 → 原因 → 解决」说清楚遇到类似情况直接对照着排查。4.1 合并后满屏乱码编码混用还是 BOM 残留现象合并出来的文件一部分段落正常一部分显示成「锟斤拷」「」这类不可读字符或者文件的某个交界处凭空多出一个空行和一个方框字符。原因分两种。第一种是编码混用部分文件是 GBK 部分文件是 UTF-8合并工具按同一种编码解读所有内容读错的文件自然乱码。第二种是 BOM 残留带 BOM 的 UTF-8 文件合并时开头的 EF BB BF 三个字节被当成正文写进输出文件在交界处表现为一个不可见字符或乱码符号。解决合并前先跑第 2.2 节的编码检查脚本把编码不一致的文件全部找出来统一转成 UTF-8 无 BOM 再做合并。如果已经合并完了可以用脚本重新处理读入原始合并文件时按 utf-8 解码失败就用 gbk 兜底再整体转成 utf-8 输出。BOM 残留的清理更简单读入时用 utf-8-sig 编码把开头三个字节吞掉写出时用 utf-8BOM 自然消失。这个坑的根源在源头所以我的习惯是编码检查脚本不离手合并之前必跑一次。4.2 第 10 卷排在 第 2 卷前面文件名排序规则不一致现象文件列表显示第 1 卷、第 10 卷、第 11 卷、第 2 卷合并结果章节顺序跳变但看目录时文件明明是按顺序排的。原因Windows 资源管理器默认自然排序文件名中的数字按数值大小排列TextForever 这类工具的文件列表往往按字典序排列字符串逐字符比较第 10 卷的「1」比第 2 卷的「2」小所以排在前面。这不是工具 bug是两种排序规则的固有差异。出错场景集中在文件名带数字编号的文件集章节名带「一、二、三」汉字的反而不受影响。解决合并前核对列表顺序发现错乱就手动上下调整文件多的时候更可靠的办法是把文件名统一补零——「第 1 卷」改成「第 01 卷」「第 10 卷」保持「第 10 卷」字典序和自然序就一致了。批量改名可以用系统自带的重命名功能也可以用一个简单脚本处理。补零之后再合并顺序问题从根上消失这个操作我每次做分卷合并都会先做一遍省心。4.3 段落合并把「第 1 章」并进正文合并前没保护标题行现象段落合并之后「第1章 风起」和正文第一句话连成了一行章节标题消失整章文本变成一坨。原因段落合并的判断规则认为「不以句号结尾的行是段内续行」章节标题恰恰符合这个特征——没有句尾标点长度短后面紧跟正文第一句。于是标题被当作上一段或下一段的组成部分拼进去。这个问题在中文网文里高频出现因为章节标题的格式和普通短行太像了。解决在段落合并之前先用正则给每个章节标题行前后各加一个空行把标题单独隔离出来。这样段落合并时空行策略会把标题当作一个独立的块而不是和正文粘连。这个预处理可以直接在 TextForever 的替换功能里完成也可以用下面的脚本import re text open(raw.txt, encodingutf-8).read() text re.sub( r^(第[0-9一二三四五六七八九十百千][章节卷回][^\n]*)$, r\n\n\1\n\n, text, flagsre.M ) open(protected.txt, w, encodingutf-8).write(text)这段正则匹配「行首是第 数字或中文数字 章/节/卷/回 任意字符到行尾」的整行在前后的换行替换成空行隔开。flagsre.M 是让 ^ 匹配每一行的行首而不是只匹配文件开头这是它生效的前提。字符类里把「一二三四五六七八九十百千」写全是为了覆盖「第一百二十章」这类中文数字编号。注意替换后标题行自身前后各多了一个空行后续段落合并时「保留空行」策略就能正确识别标题边界。4.4 几百 MB 的 TXT 打开即卡死把大文件先拆再合现象一个 800MB 的小说合集导入 TextForever界面直接未响应或者合并过程走到一半程序崩溃已合并的文件损坏。原因这类文本工具的常规实现是一次性把文件读入内存行结构、编码转换、界面显示都要占用内存。800MB 的文本进入内存后轻松超过 2GB 占用加上实时预览更是雪上加霜。大文件卡死多数是内存或单线程处理瓶颈不是文件坏了。解决先把大文件拆小再逐块处理最后合并。TextForever 自带拆分功能可以按行数或按大小把大文件切成 30-50MB 的块每一块单独做段落合并、编码转换这类操作处理完再用文件合并拼回去。另外两个实操细节合并时不要勾选「同时转码」这类加重负担的选项处理期间关掉实时预览预览是内存大户。等所有块处理完再合并速度反而比一次性处理一个大文件快得多。完成合并之后先别急着删原文件打开合并结果翻几页确认无乱码无跳章再做清理。5. 进阶用法做一个分卷小说到可训练语料的合并流水线TextForever 能把文件合并和段落合并做成「批处理式」的稳定流程但工具本身只解决形态问题不解决语义问题。我在处理「把整本小说转成可用的文本语料」时会把 TextForever 和脚本配合起来各干各的活。这个场景在实际需求里很常见比如把 txt 章节整理成统一的 instruction-input-output 格式并生成 train.json 文件用来做微调数据集。TextForever 负责形态整理脚本负责语义切片两者错开流程可控。完整流程是四步先在 TextForever 里完成文件合并输出 UTF-8 无 BOM 的整本文件再做段落合并和章节标题保护确保每个章节标题独立成行接着用脚本按「第 N 章」把整本文本切成章节块最后清洗并组装成目标格式。切章这一步是语义操作TextForever 帮不上忙我通常这样处理import json, re text open(novel_merged.txt, encodingutf-8).read() parts re.split(r(?^第[0-9一二三四五六七八九十百千]章), text, flagsre.M) data [] for i in range(1, len(parts)): seg parts[i].strip() if len(seg) 20: continue m re.match(r^(第[0-9一二三四五六七八九十百千]章[^\n]*), seg) title m.group(1) if m else f第{i}章 body seg[m.end():].strip() data.append({ instruction: 请阅读下面这章小说内容。, input: f{title}\n{body[:2000]}, output: 已阅读。 }) json.dump(data, open(train.json, w, encodingutf-8), ensure_asciiFalse, indent2)这段代码的正则部分和上一章保护标题用的是同一套思路但这里用到了零宽断言(?...)作用是匹配「第 N 章」这一行的行首位置但不消费字符分割结果里章节标题仍然保留在每一段的开头不会被切丢。参数里body[:2000]是单条样本长度上限控制单条数据不要过长len(seg) 20用来过滤掉只含标题的空白章节这类章节在分割后经常出现。输出时ensure_asciiFalse保证中文以可读形式写入 JSONindent2只是让文件便于人工检查。这套流程跑通之后我心里的那个结也解开了文件合并、段落合并这类工具价值不在于按钮本身而在于它能把「形态整理」这一步稳定地批量完成把时间和精力留给真正需要判断力的事。我现在的习惯是合并之前先跑一遍编码检查脚本合并之后先看首行、边界和末尾换行确认无误再删原文件。这个习惯救过我很多次也希望帮到你。本文还有配套的精品资源点击获取