快速答案:Notepad++ 删除重复行最快怎么做

Notepad++ 删除重复行最快的方法不用写正则。三步:

  1. Ctrl+Alt+S 另存一份副本(注意不是 Ctrl+Shift+S,那个是“全部保存”,会把改动直接覆盖回所有已打开的文件)
  2. 光标随便点一下,确保没有选中任何内容,点菜单“编辑 → 行操作 → 删除重复行”
  3. 完了。全文每个内容只留第一次出现的那一行,散落在文件任何角落的重复都算,不要求相邻

它的结果顺序是“每个内容第一次出现的位置”决定的,原顺序会被打乱。要保序去重走第三章的路 2。

只想给某一段去重,就先选中那几行,同一个命令只处理选区跨到的行。

Ctrl+Z 能撤销。文件大的时候我更倾向关掉重开,别太信撤销。


一、先看清全局:一条“脏数据 → 干净数据”的流水线

我处理脏数据的习惯是先按固定顺序走六道工序,而不是拿到文件就想“该用哪个功能”。顺序错一步,最典型的后果是去重写完发现行数只少了两行,因为行尾空格没清,去重眼里每行都不一样。

六道工序与对应菜单

工序 干什么 菜单路径 要写正则吗
1 看行尾符 确认 CRLF / LF 统一 看状态栏;不统一就“编辑 → 行尾符转换”(老一点的中文版叫“档案格式转换”,英文是 EOL Conversion) 不要
2 清空白 去行尾空格、Tab 混排 “编辑 → 空白字符操作” 不要
3 去空行 删真空行和“看着空其实有空格”的行 “编辑 → 行操作 → 移除空行(含空白字符行)” 不要
4 过滤 只留下我要的行 “搜索 → 标记”配合“搜索 → 书签” 通常一条
5 去重 删重复行 “编辑 → 行操作 → 删除重复行” 不要
6 排序 定最终顺序 “编辑 → 行操作”里的各种排序 不要

为什么顺序不能乱

第 1 步必须在最前面。 官方手册讲去重和排序时写了同一句话:这些操作假设文件里所有行尾符统一,且与当前文件设置一致。手册给的自查办法是看状态栏,那里显示 Windows (CR LF)Unix (LF) 还是 Macintosh (CR)。混用行尾符的文件,去重会漏、排序会串。改法见行尾符与 CRLF/LF 转换

第 2 步要在第 5 步前面。 行尾多一个空格,在去重眼里就是两行不同的数据。北京北京 不算重复。第三章末尾有四查清单。

第 4 步和第 5 步的先后看目的。 先过滤再去重,数据量小跑得快;先去重再过滤,能看出上游吐了多少脏数据。我一般先过滤。

哪些步骤根本不用写正则

六道工序里五道半都能点菜单解决。只有“过滤”通常要写一条规则,而且很多时候普通查找模式填个词就行(填 ERROR,勾书签行,标记全部)。

站内正则替换 15 个实例里有个原则我特别认同:能点菜单就点菜单,点不到才写正则。这篇文章基本就是这句话的展开。


二、编辑 → 行操作:这些命令多数人只用过三个

我问过身边十几个用 Notepad++ 的同事“编辑 → 行操作”里你用过哪几条,答案集中在三个:升序排序行、Ctrl+DCtrl+L。剩下那一半,几乎没人点开过。

完整命令清单

官方手册的编辑菜单章节整理。中文菜单名各版本略有出入,认不准看英文那列。

菜单项 英文 作用范围 说明
升序 / 降序排序行 Sort Lines Lexicographically Ascending / Descending 选区跨到的行,无选区则全文 按字符编码逐个比,见第四章
升序排序行(忽略大小写) …(Ignore Case) 同上 大小写混排的名单
升序排序行(区域语言顺序) …(Locale Order) 同上 v8.8.1 新增,中文排序用它
按整数升序 / 降序 Sort Lines As Integers Ascending / Descending 同上 解决 “100 排在 2 前面”
按小数升序 / 降序(逗号 / 点号) Sort Lines As Decimals (Comma) / (Dot) 同上 欧洲用逗号,中美用点号
按行长升序 / 降序 Sort Lines By Length Ascending / Descending 同上 v8.8.9 新增
倒序排列 Reverse Line Order 选区或全文 v8.0.0 新增,纯翻转不比较内容
随机打乱行顺序 Randomize Line Order 选区或全文 造测试数据
删除重复行 Remove Duplicate Lines 选区跨到的行,无选区则全文 全局去重,会清空全文书签
删除连续重复行 Remove Consecutive Duplicate Lines 同上 只删紧跟在后面的重复
移除空行 Remove Empty Lines 全文 只删零字符的行
移除空行(含空白字符行) Remove Empty Lines (Containing Blank characters) 全文 只有空格 / Tab 的行也删
上移 / 下移当前行 Move Up / Down Current Line 当前行或选中行块 Ctrl+Shift+↑ / Ctrl+Shift+↓
复制当前行 Duplicate Current Line 当前行 Ctrl+D,v8.6 起忽略选区状态
删除当前行 Remove Current Line 当前行 Ctrl+L
合并行 Join Lines 需跨两行以上的选区 Ctrl+J,换行换成空格
拆分行 Split Lines 选区或光标所在行 按右边界或窗口宽度断行

跟空白有关的命令不在这里,在“编辑 → 空白字符操作”,见第六章。

两个去重命令到底差在哪

中文菜单里它们只差两个字,但完全是两回事。

“删除重复行”(Remove Duplicate Lines):官方手册原话是只保留全文中出现多次的整行里的第一个实例,其余全删。关键词是 “anywhere in the active file”,不管相不相邻,内容一样就只留第一行。

“删除连续重复行”(Remove Consecutive Duplicate Lines):只删紧跟在第一个实例后面的重复行。第 1 行和第 500 行内容一样,它一个都不删。

两条是并列关系,从来都是独立的菜单项,不是新旧版本关系。正则替换 15 个实例案例 5 用的是后者,那篇的核心是正则和“排序后删连续”,这里不重复。

官方注记:删除重复行会清空全文书签。 手册里有一句中文互联网上我没见人提过的话:因为实现方式的关系,这个命令会清空当前文件的所有书签。

这对用书签做行过滤的人是暗雷。有一次我先 Mark 出所有含 ERROR 的行打上书签,中途手滑点了一次“删除重复行”,书签全没了,接下来点“删除未标记行”差点把整个文件清空。我的做法是把“删除重复行”放到书签用完之后,或者点之前先另存。

连续去重那条也不干净:它不清空书签,但如果某个带书签的行正好被当成连续重复删掉了,那个书签会留在原来的行号上,也就是说它现在指向原本排在它后面的那一行。行数一多,这种偏移靠肉眼发现不了。

只对选区生效的坑

两个去重命令、所有排序命令,都是“有选区就处理选区跨到的行,没选区就处理全文”。听起来贴心,踩坑率很高。

经典事故:选区多带了一行。 你想去重第 5 到第 10 行,鼠标从第 5 行行首拖到第 10 行,手抖拖到第 11 行最前面一点点,选区末端落在第 11 行第 1 列。这时候选区“跨到”了第 11 行,那行也被纳入去重范围,如果恰好重复就被删了,而你不知道。从上一行行尾开始选,起点那行也会被算进去。

我的习惯是选完看一眼状态栏,或者 Ctrl+G 跳行号配合 Shift+↓ 整行选,不拖鼠标。

另外“移除空行”和“移除空行(含空白字符行)”不认选区,永远作用于整个文档。想只删某一段里的空行,没有内置办法。


三、Notepad++ 删除重复行:不写正则的三条路

Notepad++ 删除重复行有三条不写正则的路。先说边界:用正则删连续重复行、以及“排序 + 删除连续重复行”这套组合拳,正则替换 15 个实例案例 5 讲得很细了,包括为什么只能删相邻的、排序的代价是什么。本章讲它没给的那几条路。

那篇最后留了句话:想既保序又全局去重,得装 Python Script 写五行代码,“这是正则的能力边界,绕不过去”。后半句我不同意。下面路 2 用纯内置功能就能做到,一行插件都不用装。

路 1:内置一键全局去重(不在乎顺序时最快)

适用:名单、字典、配置项、IP 集合这类“顺序无所谓,只要不重”的数据。

操作跟开头快速答案一样:另存 → 不选中任何内容 → “编辑 → 行操作 → 删除重复行”。

要排序的话去重前后各点一次都行。我习惯先排序再去重,重复行挨在一起时跑得更快,上万行能感觉到差别。

结果顺序是什么样? 不是原顺序,也不是排序后的顺序,是“每个内容第一次出现的位置”决定的。文件看着会比较乱。最终要排序就无所谓,不排序就基本没法看。

最终要排序就用路 1,不排序看路 2。只想给某一段去重就先选中那几行,选区边界的坑见第二章。

路 2:保序去重四步法(行号锚定)

我这两年用得最多的一套动作,目标是全局去重,保留每组第一个(原始文件里最早出现的那行),行间相对顺序完全不变

思路是:给每行钉一个行号当“记忆”,然后放心排序,排完再按行号排回来。

严格说是五步,我把最后两个动作算成一步收尾。

前置:先移除空行,并确认行尾符统一。空行会打乱列操作,行尾符混用会让去重漏内容。

第 1 步:给每行钉上行号

  1. 光标放到第 1 行行首(Ctrl+Home
  2. 按住 Alt+Shift 再按 拉到最后一行,行太多就先 Alt+Shift+PageDown 翻页。手册还列了第三种:光标放到起点,执行一次“开始/结束列模式选择”(英文菜单是 Begin/End Select in Column Mode,中文名各版本译法不一),再把光标移到终点执行一次。它可以在两次执行之间随便翻页,几万行的文件用这个最省事。基本操作见入门篇的列编辑
  3. Alt+C 打开列编辑器,数字区域填初始 1、增量 1、重复 1,把“前导零”打开,确定。这个选项在 v8.5.2 之后叫 Leading 下拉框,选 Zeros;再老的版本是个“前导零”复选框,勾上就行。两种我都见过,都在数字区域里
0001北京
0002上海
0003北京
0004广州

怎么确认选区做对了:直接看 Alt+C 的结果,行号是不是插到了每一行的第 1 列。零宽列选区里一个字符都没有,官方手册对它的定义是“只由贯穿多行的光标组成”(consisting only of a caret extending through multiple lines),界面上通常看不出选中效果,别指望肉眼确认;如果行号只插在第 1 行,说明选区没建起来,按 Esc 重来。

行号宽度按行数定,这一步不能省:9,999 行以内用 4 位(正好 1 万行就得用 5 位),10 万行以内用 6 位。宁可多一位别少。宽度不够时第 10000 行之后的行号会溢出成 5 位,第 4 步“按行号排回”整段错位,而且不报错

用 5 位的话,后面三步要跟着改:第 2 步列号放第 6 列、第 3 步正则用 {5}、第 4 步删前 5 列。别照抄 4 位的参数。

第 2 步:按内容排序,让重复项挨在一起

关键是排序键只取内容,不含行号

  1. 光标放到第 1 行第 5 列(行号后面第一个字符)。4 位行号是第 5 列,6 位是第 7 列
  2. 同样用 Alt+Shift+↓ 拉到最后一行,做出零宽列选区
  3. “编辑 → 行操作 → 升序排序行”

手册的说法是:排序会重排选区覆盖到的所有行,排序键限制在列选区内部;列选区零宽时,每行的键从光标右边第一个字符延伸到行尾。翻成人话,排序键正好是去掉行号后的内容。而且手册明确写了,这种基于列选区的排序是稳定排序,键相同的两行先后顺序不变。

0002上海
0001北京
0003北京
0004广州

注意“上海”跑到最前面了,“上”的字符编码比“北”小。跟按拼音想的完全不一样,第四章说的就是这事。

排完先自查一眼北京 这一组里两行是 1、3,递增的。递增说明零宽列选区做对了、稳定排序生效了;不递增就是选区歪了,Ctrl+Z 重来。这条自查比看界面有用得多,因为选区本身可能看不见。

某行内容为空时光标会落到行尾,排序键是空串,这类行会聚到最前面。

排序没反应就去看“设置 → 首选项 → 编辑”里把列选择转成多编辑的开关(v8.6 起有),开着会让排序键失效。

第 3 步:删掉每组里多余的行

现在整行是“行号 + 内容”,互不相同,两个内置去重命令都用不了(它们比整行)。这一步用一条正则,只比内容部分

查找串(4 位行号版)

^(.{4})(.*)(\R.{4}\2)+$

替换串

\1\2

6 位行号就把两个 {4} 都改成 {6}

  • \1 行号,\2 内容,(\R.{4}\2)+ 匹配一行或多行“换行 + 行号 + 相同内容”
  • 保留的是每组第一行,也就是行号最小的那行,正是原始文件里最早出现的
  • 搜索模式选“正则表达式”;\R 需要 7.9 以上版本,站内正则替换 15 个实例用的也是它
  • . matches newline 千万别勾,勾了 .* 会跨行

最后一行没有换行符:按理 $ 能匹配到缓冲区末尾,但我没验证过。不放心就在文件末尾敲个回车,跑完再删。

0002上海
0001北京
0004广州

第 4 步(收尾):排回原顺序 + 摘掉行号

  1. 先按 0(或点一下正文任意位置),确认第 2 步的零宽列选区已取消。手册说排序不会自动清掉列选区,带着列选区做这一步,排序键又会变回内容,整套方法失效
  2. “编辑 → 行操作 → 升序排序行”,不要任何选区。行号等宽且排在最前,按字符编码升序就等于按行号数值升序
  3. 用列编辑(Alt 拖选前 4 列)选中所有行号,按 Delete
北京
上海
广州

跟原始文件里第一次出现的顺序一模一样,这就是“保序”的意思。

什么时候不划算:上万行且重复率很低时,第 2 步的列选区排序会慢,第 3 步的正则也有回溯开销。我的经验是几千行以内很顺,几万行明显卡,那时候考虑 Python Script 或者导出到数据库 SELECT DISTINCT

路 3:按某一列去重

场景:CSV 名单里手机号重复,姓名城市不同,想按手机号去重,保留每个号码第一次出现的那行。

这条路是路 2 的推广,只改第 2 步:排序键从“去掉行号的内容”换成某一列

1001,张伟,13800138001,杭州,线下活动
1002,李娜,13800138002,北京,官网注册
1003,王强,13800138001,上海,线下活动
  1. 按路 2 第 1 步钉上等宽行号
  2. Alt 拖选手机号那一整列(字段宽度不齐就先在 Excel 里对齐,实在对不齐就退回用正则)
  3. “编辑 → 行操作 → 升序排序行”,排序键就是手机号列,稳定排序保证同号码组内保持原顺序
  4. 正则删组内多余行,跳过行号和前两列,只比手机号
^(.{4}[^,]*,[^,]*,)([^,]*)(,.*)(\R.{4}[^,]*,\2,.*)+$

替换串 \1\2\3

  1. 按行号排回,列编辑删掉行号

诚实讲,第 4 步这条正则已经不算“不用写正则”了,可读性也一般。我只在不方便装插件、又确实要按列保序去重时用它。这类活每周都有就老实写脚本。

两个官方警告:选区内或选区左边有 Tab 字符、或者有多字节字符(中文就是)时,列选区排序结果可能不符合预期。中文 CSV 上做列排序,先确认分隔符是逗号不是 Tab,再用等宽字体看一眼对齐。

去重失败?按顺序查这四项

跑完发现行数没变或只少两三行,别急着怀疑命令坏了,按这个顺序查:

1 大小写。 Errorerror 是两行。内置去重逐字节比较,不忽略大小写。想忽略先“编辑 → 转换大小写为”统一成小写。

2 尾随空格。 最常见。从 Excel、网页、PDF 复制出来的数据,行尾常挂一两个空格,肉眼看不见,去重看得见。先跑“编辑 → 空白字符操作 → 移除尾随空格”。

3 行尾符混用。 手册在去重那段特别注明:去重假设全文行尾符统一。一半 CRLF 一半 LF 的文件,去重结果会莫名其妙。看状态栏确认,不统一就用“编辑 → 行尾符转换”,原理见行尾符与 CRLF/LF 转换

4 全角半角。 中文数据的经典坑:,()()、全角空格(U+3000)和半角空格,字节层面完全不同。从网页或微信粘过来的名单,全角比例高得离谱。查的办法是开“视图 → 显示符号 → 显示空格和 Tab”,全角空格显示成小方块,跟半角的点不一样。

什么时候必须改用正则

需要“按某个模式去重”而不是“按整行去重”时。两行内容不完全一样但属于同一条记录(时间戳不同、ID 不同),只按其中一段判重,内置的比不了。回到正则替换 15 个实例案例 5,把思路改成“捕获要判重的那一段”。


四、排序:为什么 100 会排在 2 前面

用 Notepad++ 排序时我第一次遇到这事,是在排一份端口清单,排完发现 1002 前面、8080443 前面。当时以为是 bug,其实是我选错了排序方式。

原因很简单:默认的“升序排序行”按字符编码逐个比。1 的编码比 2 小,所以 1001000 全排在 2 前。它不认识数字,只认识字符。

9 种排序变体速查

排序方式 什么时候用 版本
按字符编码(Lexicographically) 纯英文、或位数相同的纯数字 全版本
忽略大小写(Ignore Case) 大小写混排,想让 appleApple 挨一起 全版本
区域语言顺序(Locale Order) 中文、带重音的欧洲语言 v8.8.1 新增,官方 changelog 有这条
按整数(As Integers) 纯数字列,解决 100 排在 2 全版本
按小数(逗号 / 点号) 欧洲写法 10,234 / 中美写法 10.234 全版本
按行长(By Length) 找异常行、按长度分组 v8.8.9 新增,官方 changelog 有这条
倒序(Reverse Line Order) 不比较内容,纯翻转行序 v8.0.0 新增
随机(Randomize Line Order) 造测试数据、随机抽样 全版本

除倒序外每种都有升序降序两条。中文菜单里名字各版本略有出入,认准 Ignore CaseLocaleIntegersDecimalsBy Length 这几个词就不会点错。

几条手册里的注记:

  • 按整数排序会把 IP 排得比较合理,8.8.8.8192.168.0.1 前面
  • 按整数排序能处理“相同非数字前缀 + 数字”,xyz9xyz11 前面
  • 右对齐数字会被空格坑 1 10 1001000 按整数排会得到 100 10 11000。带一个空格前缀的整数排在带两个空格的后面,没空格前缀的 1000 反而最后。排序前先“移除行首空格”能避开

按列排序:列选区作为排序键,且是稳定排序

第三章路 2 已经用过,单独拎出来是因为值得单独记。

操作:Alt 拖出一个列选区(或零宽列选区)覆盖你想当排序键的那一列,然后点任意一条排序命令。手册说法是:排序会重排列选区覆盖到的所有行,排序键限制在列选区内部;零宽时每行的键从光标右边第一个字符到行尾。

手册明确写了这是稳定排序:两行键相同时先后顺序不变,即使键之外的文本不一样。

用处在哪:一份 CSV 按城市列排序,同一城市内部会保持文件里的原始顺序(比如录入时间)。配合列编辑一起用,这一条能解决不少“看着要写脚本才能干”的活。

中文排序用 Locale Order

最容易踩的坑:用默认“升序排序行”排中文名单,得到的是按字节序排的结果,既不是拼音也不是笔画,看着完全随机。

v8.8.1 加进来的区域语言顺序(Locale Order)就是解决这个的,官方描述是“提供符合语言习惯的字母序排序”,调用 Windows 区域排序规则,中文环境下按拼音排。北京 会排在 上海 前面。

另外两条:

  • Locale 排序不受行尾符限制。手册特别注明,除 Locale 外其余排序都假设行尾符统一
  • Locale 排序本身是稳定排序,而且会把数字当数字处理,排 第2章第10章 也对

排序依据的是 Windows 控制面板“区域”里的设置。

排序前先统一行尾符

手册在排序那段重复了和去重一样的警告:除 Locale 排序外,排序假设全文行尾符统一且与当前设置一致。查法一样看状态栏,不统一就“编辑 → 行尾符转换”,或右键点状态栏行尾符指示器直接改。原理见行尾符与 CRLF/LF 转换

动手前先另存

排序不可逆。不是撤销不了,是你不一定记得原顺序是什么。几千行日志排完,你根本看不出它原来什么顺序,而 Ctrl+Z 只能在你意识到错误之前救你。Ctrl+Alt+S 两秒钟的事。


五、行过滤:只留下我要的行

Notepad++ 的行过滤是流水线里唯一常要写规则的一步,但写的东西可以很简单,而且有一条完全不用正则的路。

书签流:一条都不用写

假设要从日志里挑出所有含 ERROR 的行:

  1. Ctrl+F 打开查找,切到“标记”标签页
  2. 查找内容填 ERROR(不用勾正则,普通模式够)
  3. 勾选“书签行”
  4. 点“标记全部”

所有匹配行带上书签,行号左边有蓝色圆点,状态栏告诉你标记了多少行。然后“搜索 → 书签”里有五条命令,组成完整流水线:

命令 作用 什么时候用
复制书签行 把标记的行复制到剪贴板 提取到新文件(最常用)
剪切书签行 剪走标记的行 原文件里要删掉它们
删除书签行 删掉标记的行 这些行是垃圾
删除未标记行 只留下标记的行 反向操作
反向书签 书签取反 多轮过滤时用

“复制书签行”我用得最多,它不改动原文件,结果放剪贴板,Ctrl+N 新建标签、Ctrl+V 粘贴,原始文件原封不动。

“反向书签”是多条件过滤的关键,但用法不是你想的那样:Mark 会在全文范围内匹配,“书签行”只是把书签加到匹配行上,不会自动做交集。正确做法看下面。

正则流:保留匹配行与删除匹配行

需要按模式过滤时,Mark 里勾“正则表达式”,写一条规则,剩下流程完全一样。

目的 查找串 之后的操作
挑出错误和警告 `\[(ERROR\ WARN)\]` 标记全部 → 复制书签行
挑出非空行 ^.+$ 标记全部 → 删除未标记行
挑出长度超 200 的行 ^.{201,}$ 标记全部 → 复制书签行
挑出含 IP 的行 \d{1,3}(\.\d{1,3}){3} 标记全部 → 复制书签行

删除未标记行 就是“保留匹配行”,删除书签行 就是“删除匹配行”。名字绕,记住“未标记”三个字就行。更多写法在正则替换 15 个实例

多条件“且”

Mark 一次只能一个条件,想实现“A 且 B”有两招。

招一:两轮书签取交集。 Mark 条件 A 打书签 → “删除未标记行” → “清除所有书签” → Mark 条件 B 打书签 → “删除未标记行”,剩下的就是 A 且 B。代价是原文件其他内容没了,所以第一步改用“复制书签行”把 A 提取到新标签再做第二轮。

招二:一条正则写两个条件。 用正向预查把“且”塞进一条里,比如“含 ERROR 且含 timeout”:

^(?=.*ERROR)(?=.*timeout).*$

(?=...) 是“这个位置后面必须能匹配到”,两个预查叠起来就是同时满足。语法细节在正则替换 15 个实例

我一般用招二,一条搞定不用来回倒文件。条件超过三个时正则很难读,换招一。

剪贴板闭环

过滤最后一步很关键:把结果提取到新标签,再在新标签上做二次处理。

动作:标记全部 → 复制书签行 → Ctrl+NCtrl+V → 在新标签上去重、排序、加前缀。好处是原文件永远干净,而且新标签行数少,后续操作快得多。复制出来的内容末尾会多一个空行,跑一次“移除空行”就行。


六、清洗四件套:只用内置菜单

这章只讲 Notepad++ 内置菜单能点到的。正则版本(行首空格、空行压缩、全文大小写)在正则替换 15 个实例里,不重复。

空白字符操作命令清单

注意这组不在“行操作”里,在“编辑 → 空白字符操作”。很多教程把它们混写,害人找半天。

菜单项 英文 作用
移除尾随空格 Trim Trailing Space 删行尾空格和 Tab
移除行首空格 Trim Leading Space 删行首空格和 Tab(别在 Python 文件上跑
移除首尾空格 Trim Leading and Trailing Spaces 两头一起删
行尾符转换为空格 EOL to Space 换行换成空格,等于全文合并成一行
移除多余空白和行尾符 Trim Both and EOL to Space 去首尾空格再合并行。v8.4.9 前叫 Remove Unnecessary Blank and EOL
Tab 转空格 TAB to Space Tab 换成等价数量空格
空格转 Tab(全部) Space to TAB (All) 所有连续空格合并成 Tab
空格转 Tab(行首) Space to TAB (Leading) 只转行首缩进部分

“行尾符转换为空格”容易和“行操作”里的“合并行”搞混:合并行只处理选区,行尾符转换为空格作用于整个文档。

一个反直觉的行为:手册说 Trim 类命令作用于“选区所在的行”,即使选区没包含那些首尾空格。一行内容是“几个空格 + words here + 几个空格”,你只选中 words,跑“移除首尾空格”,行首行尾照样被删。

大小写转换 8 种

“编辑 → 转换大小写为”下面有 8 条,不是通常以为的 4 条:

菜单项 效果(以 hello world 为例) 快捷键
UPPERCASE HELLO WORLD Ctrl+Shift+U
lowercase hello world Ctrl+U
Proper Case Hello World Alt+U
Proper Case (blend) 同上,但保留已存在的大写 Alt+Shift+U
Sentence case Hello world Ctrl+Alt+U
Sentence case (blend) 同上,但保留已存在的大写 Ctrl+Alt+Shift+U
iNVERT cASE 逐字母翻转大小写
ranDOm CasE 随机大小写

blend 版本的区别值得说:普通 Proper Case 会把 iPhone 变成 IphoneMySQL 变成 Mysql;blend 版本保留词里已存在的大写,iPhone 还是 iPhone

iNVERT cASE 翻转每个字母大小写,HellohELLOranDOm CasE 每次结果都不一样,没法复现。清洗数据我基本不用这两个。

只有 iNVERT cASEranDOm CasE 没有默认快捷键,其余六条都有。官方手册的“转换大小写为”一节没记录任何快捷键,上面这几个是我机器上和社区快捷键表里一致的绑定;按了没反应就去“设置 → 快捷键映射器”看实际绑定。

空白操作默认作用于整个文档,v8.4.9 起才支持选区

手册里的一条总注,也是容易出事的地方:

  • 默认情况下所有“空白字符操作”命令作用于整个文档,不管有没有选区
  • v8.4.9 起,如果有一个普通流式选区,操作只作用于选中文本
  • 多个选区(多光标)时,只有最后添加的“主选区”受影响
  • 列选区时不执行任何 trim 或 Tab 转换

最后一条最坑:你以为选中一列跑 trim,结果要么什么都没发生,要么它作用于全文了。想给某一列做 trim,没有内置办法,只能先把那列复制出来单独处理。

判断版本看“? → 关于”。低于 v8.4.9 的话所有 trim 都是全文操作,动手前一定先另存。


七、实战:三条完整流水线

三个案例都用 Notepad++ 跑过,数据脱敏过。步骤按真实操作顺序写。

案例 1:大日志 → 几十行错误摘要

输入:12 万行 Java 日志,混着 INFO、WARN、ERROR,行长 150 到 400 字符。目标:拉出所有 ERROR,去重,看一共几种错误。

2026-08-14 09:12:03.441 [http-nio-8080-exec-7] INFO  c.e.order.service.OrderService - order created id=20260814000123
2026-08-14 09:12:03.902 [http-nio-8080-exec-7] ERROR c.e.order.service.PayService - pay timeout orderId=20260814000123 channel=WEIXIN
2026-08-14 09:12:04.117 [http-nio-8080-exec-9] WARN  c.e.order.service.StockService - stock low sku=SKU-88213 remain=3
2026-08-14 09:12:05.003 [http-nio-8080-exec-7] ERROR c.e.order.service.PayService - pay timeout orderId=20260814000125 channel=WEIXIN

第一步:看行尾符。 状态栏显示 Unix (LF),全文统一,跳过。

第二步:只留 ERROR 行。 Ctrl+F → 标记 → 填 ERROR → 勾“书签行” → 标记全部。状态栏显示标记了 3,842 行。

第三步:提取到新标签。 “搜索 → 书签 → 复制书签行”→ Ctrl+NCtrl+V,存成 errors.txt。原文件关掉不动。

第四步:抹掉时间戳和线程名,否则每行都不一样,去重没意义:

^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+ \[[^\]]+\] ERROR 

替换串留空。剩下 c.e.order.service.PayService - pay timeout orderId=20260814000123 channel=WEIXIN

第五步:把订单号也抹掉,不然每个订单一条还是去重不掉:orderId=\d+ 替换成 orderId=Xchannel=\w+ 同理,看你要不要保留渠道信息。

第六步:去重。 “编辑 → 行操作 → 删除重复行”。3,842 行变 27 行。

这个案例的精髓在第四、五步。 日志天然每行唯一(有时间戳),直接去重一行都删不掉,必须先“归一化”把不该参与比较的字段抹平。这步想不明白,去重命令点一百次也没用。

案例 2:Excel 导出 CSV → 干净名单

输入:3,600 行 CSV,三个来源合并,重复严重,行尾带空格,中间夹空行。

序号,姓名,手机号,城市,来源
1,张伟,13800138001,杭州,线下活动
2,李娜,13800138002,北京,官网注册

3,王强,13800138001,上海,线下活动
4,张伟,13800138001,杭州,线下活动 

第一步:另存。 Ctrl+Alt+S 存成 contacts_raw.csv

第二步:清空白。 “编辑 → 空白字符操作 → 移除首尾空格”,干掉最后一行 线下活动 末尾那个空格。

第三步:去空行。 “编辑 → 行操作 → 移除空行(含空白字符行)”。

第四步:按手机号去重。 走第三章路 3。手机号是第 3 列且都是 11 位等宽,Alt 拖列选区能对齐,省掉补空格那一步:

  • Alt+Shift+↓ 拉出零宽列选区 → Alt+C 插 1 到 3600,4 位前导零
  • Alt 拖选手机号那一列 → “升序排序行”,稳定排序让同号码组内保持原顺序
  • 正则删组内多余行:^(.{4}[^,]*,[^,]*,)([^,]*)(,.*)(\R.{4}[^,]*,\2,.*)+$\1\2\3
  • “升序排序行”按行号排回,列编辑删掉行号

结果:3,600 行 → 2,914 行。表头如果在合并时重复过,第四步顺手就去了。

踩过的坑:第一次做这份数据我跳过了第二步,只删掉 200 多行;补上“移除首尾空格”之后删到 600 多行。行尾一个空格,能让去重能力打三折。

案例 3:几千行配置 → 提取 IP 并排序去重

输入:4,800 行 Nginx 配置,IP 散落在十几个 upstream 块和 allow 规则里。目标:拉出所有后端 IP,去重,按 IP 数值排序。

upstream api_order {
    server 10.20.31.11:8080 weight=5;
    server 10.20.31.12:8080 weight=5;
    server 10.20.31.11:8080 backup;
}

location /api/ {
    allow 10.20.40.5;
    allow 192.168.100.200;
    deny all;
}

第一步:挑出含 IP 的行。 Ctrl+F → 标记 → 勾“正则表达式” → 填 \b\d{1,3}(\.\d{1,3}){3}\b → 勾“书签行” → 标记全部。

第二步:复制到新标签。 “搜索 → 书签 → 复制书签行”→ Ctrl+NCtrl+V,得到约 180 行。

第三步:删掉 IP 之外的部分。

^.*?(\d{1,3}(?:\.\d{1,3}){3}).*$

替换串 \1.*? 是懒惰匹配,保证抓每行第一个 IP。

第四步:去重。 “编辑 → 行操作 → 删除重复行”。180 行 → 43 行。

第五步:按 IP 数值排序。 必须用“按整数升序排序”,不能用默认的按字符编码。手册里明确写了按整数排序会把 IP 排得比较合理。用默认排序时 10.x192.x 的结果看着像对的,纯属巧合,换成 10.x9.x 就露馅了。

结果:43 个唯一 IP,按数值排好,直接贴进巡检表。价值在第三步和第五步的组合:提取(正则)+ 去重(内置)+ 排序(选对变体)。


八、TextFX 已经不能用了

从七八年前的教程过来的话,大概率见过推荐装 TextFX 做排序、去重、大小写转换的内容。现在不用找了。

发生了什么

第一层:从来就没有 64 位版。 TextFX 最后一个官方版本是 0.2.6,发布于 2009 年,那一年还没有 64 位版 Notepad++(64 位是 v7.0 才有)。所以它从来没在 64 位上被官方支持过。

第二层:v8.4.3 起被主动禁用。 这一层很多人不知道。2022 年 7 月的 v8.4.3 之后,Notepad++ 会主动禁用机器上残留的旧版 TextFX,插件从菜单里消失,插件列表也搜不到。

官方理由是:这个插件的某些操作会让 Notepad++ 崩溃,而编辑器崩溃对数据完整性有风险。原话大意是“插件动作导致崩溃,这对数据完整性很危险”。

技术根因是 Scintilla 5.1.5 改了一个 API 的返回值语义:SCI_GETCURLINESCI_GETTEXT 这类消息不再返回末尾多出的那 1 字节。Notepad++ v8.4 跟着升到 Scintilla 5.x,TextFX 里所有依赖旧行为的代码路径就全错位了,而它停更十几年,没人修。

所以这不是“兼容性警告”,是“装上会把文件搞坏,所以不让你装”。残留的旧文件留着不碍事(不会被加载),降级回 v8.4.2 能复活,但意味着永远不升级。

功能替代对照表

官方社区的 TextFX 功能替代清单有一份完整对照,我按“用什么替代”整理,并加了一列我的建议:

TextFX 原功能 现在怎么做 我的建议
排序行 “编辑 → 行操作”9 种变体 内置,比 TextFX 强
删除重复行 “编辑 → 行操作 → 删除重复行” 内置全局去重,TextFX 当年做不到
大小写转换 “编辑 → 转换大小写为”8 种 内置,还有 blend 版本
移除空行 / 尾随空格 “编辑 → 行操作”“编辑 → 空白字符操作” 内置
引号转换 正则替换,或录宏 一次性用正则,常做就录宏
行操作组合动作 录一个宏把几步串起来 宏最划算
复杂条件行处理 PythonScript 写脚本 重复超过三次就写脚本
就是想要 TextFX 界面 NPPTextFX2(第三方移植) 见下面

NPPTextFX2GitHub 上的第三方移植版,作者在 README 里说 64 位版本功能已完整(2026 年 2 月更新过)。我没在 64 位上逐条试,以你实际装到的版本为准。

我的看法:先查这张表,八成已被内置覆盖。真找不到替代再考虑 NPPTextFX2,别把它放进每周都要跑的流程里。


九、什么时候该换工具

Notepad++ 处理文本有明确舒适区,出了这个区,硬撑的时间成本会超过学个新工具。

行数阈值。 我的经验值:几万行以内上面所有操作都还流畅。十万行往上,删除重复行 和排序明显卡顿,正则里 (\R...)+ 这类有回溯的模式可能跑几十秒甚至假死。超过 50 万行我会先切文件或者换工具。这阈值跟机器配置关系很大,当参考别当标准。

需要分组聚合时。 “按城市统计每个城市多少条”这类活在 Notepad++ 里做是自己找罪受,不如一行 SQL:

SELECT city, COUNT(*) FROM contacts GROUP BY city ORDER BY COUNT(*) DESC;

数据能进 SQLite 就进 SQLite,一行 GROUP BY 顶你半小时。

需要真正的 diff 合并时。 Compare 插件能对照差异,但我的体验是它没有一个顺手的“把所有差异一次性导出”的用法,得手动一条条跳。真要做合并评审,用 VS Code 的对比或者 Beyond Compare 更省事。

需要保留处理历史时。 清洗流水线跑完,你很难说清这文件经过了哪几步。要交付给别人、或者下周还要重跑的活,写成脚本比记一串菜单点击可靠得多。

一句话判断:一个操作要重复三次以上,就值得写成脚本或宏。


下一步

这篇文章覆盖“编辑 → 行操作”“编辑 → 空白字符操作”“搜索 → 书签”这条线。往回补基础看Notepad++ 入门教程(界面、列编辑、多光标、快捷键),往前走看正则替换 15 个实例行尾符与 CRLF/LF 转换

三个常被问到的问题:

删除重复行能保留最后一次出现的那行吗? 内置命令不行,它只保留第一次出现的。要保留最后一次,先“编辑 → 行操作 → 倒序排列”把文件翻转,跑完去重再倒序翻回来。倒序之后“第一次出现”就变成了原来的“最后一次”。

点了删除重复行,行数一个没变,是命令坏了吗? 大概率不是。按第三章末尾的四查清单走一遍:大小写、尾随空格、行尾符混用、全角半角。九成是尾随空格。

能只排序文件的一部分吗? 能。选中那几行再点排序命令,只有选区跨到的行参与排序。注意选区末端别多带一行,见第二章末尾。

还有没解决的问题去常见问题看看。


还想看更多 Notepad++ 教程?

回到教程总入口,5 篇长文专题一次看全,从入门到进阶都不绕路。

查看全部使用教程
使用教程