Notepad++正则表达式批量给十六进制数字加0x前缀实践指南
1. 为什么批量加0x会变成刚需上周处理一批嵌入式设备的通信日志时我盯着满屏的A1 3F 2C 88 0B D4犯了好一阵子愁。设备的寄存器地址、固件补丁片段、存储器导出内容全是不带前缀的裸十六进制数字而我要把它们全部整理成带0x前缀的格式再填进C语言数组或者写进演示用配置表。手动一个个敲几百个数据点改下来既无趣又极容易出错但凡一个A1漏了前缀后面整段数据就全对不上。那时候我想肯定有大量同行也遇到过这种批量转换裸十六进制数字为带0x前缀的场合。后来就用 Notepad 配合正则表达式把这件事彻底解决了。整个过程不超过十秒钟。你只需要打开搜索替换框给对匹配规则一次替换就能把整份文件里符合条件的所有十六进制数字加上0x前缀而且还能顺手做大小写统一、补零对齐、批量去掉前缀等一连串操作。如果你平时要处理协议日志、单片机寄存器定义、测试向量、GBA模拟器内存地址、颜色代码这类文本这个方法能让你的效率提升一个量级。写这篇内容的目的也很简单我把这个思路完整拆开从正则匹配原理到各种场景的实操替换方案再到我实际踩过的坑全部记录下来。无论你是刚接触 Notepad 的初学者还是已经熟练使用它有一段时间的人这篇文章都能让你在快速给十六进制数字加前缀这件事上少走很多弯路。2. 匹配十六进制数字的正则思路先学会准确选中再谈替换在 Notepad 里做这件事核心不在于替换动作本身而在于你给的查找目标是否覆盖了你想要的每一段十六进制数字、同时又不误伤文件里其他内容。2.1 十六进制数字的正则长相十六进制数字由0-9和A-F大小写均可组成。如果你要匹配一个十六进制数最基本的正则就是[0-9A-Fa-f]这只是匹配单个字符。想要匹配一个完整的十六进制数而不是单个字符就在后面加一个[0-9A-Fa-f]这个正则可以匹配A1、3F、2C、FF、DEADBEEF也能匹配123。它匹配的是连续出现的十六进制字符序列也就是说A1会被视为一个整体而不会拆成A和1两段。但这里有一个非常重要的细节单独使用这个正则会在文件里到处乱撞。比如一句话里写着AB测试正则[0-9A-Fa-f]就会匹配到AB因为A和B本身就是十六进制字符。同样question里的e虽然是小写字母表里的e但它不在[0-9A-Fa-f]的范围内实际上e不在 A-F 区间里可face里的f、a、c、e中的f、a、c都在十六进制字符范围内同样会被误匹配。所以在加0x前缀之前你要先让这个正则知道我匹配的这段十六进制字符它得是独立存在的一个数而不是某个英文单词的一部分。2.2 用单词边界\b限定匹配范围Notepad 的正则引擎支持\b这个特殊符号它表示单词边界。简单说它就是用来标记一个有单词字符和没有单词字符之间的位置。在这里\b能精准地告诉我们一个十六进制数跟前后的其他字符是分开的。完整的正则写法\b[0-9A-Fa-f]\b举个例子假设你文件里有这段文字寄存器 A1 当前值 0B地址 3F状态 FF用\b[0-9A-Fa-f]\b去匹配得到的结果是A1、0B、3F、FF全部命中。而寄存器这行中文里不会匹配任何东西因为中文字符不满足[0-9A-Fa-f]的取值条件地址这个词里的A也不会单独被选中因为A在这个上下文里不是独立单词它紧跟在址字后面前后都不存在英文单词边界。不过\b在这里有一个在特定场景下会翻车的边界细节。\b判断的是单词字符的边界而A、B、C、D、E、F这六个字母恰恰也是单词字符。如果你处理的内容里有ACE、DEAL、BAD这类正常的英文单词正则照样会把它们当成十六进制数匹配上。这就要结合你的使用场景来考虑纯数据文件中一般不会出现这种问题但包含自然语言文本的文件就极有可能误伤。更稳的办法是自定义前后边界条件这个放到后面翻车现场那节详细说。2.3 替换规则$0表示原封不动的匹配内容在 Notepad 的替换框里$0代表当前被匹配到的完整内容。比如你匹配到了A1那么$0就等于A1。你要做的就是给这个结果前面粘上0x0x$0这一个替换表达式就能把所有匹配到的十六进制数字都变成0xA1、0x0B、0x3F、0xFF这样带前缀的形式。注意这里0x后面不用加空格直接紧挨着$0这样替换出来的结果才是合法的C语言十六进制字面量。你要是手滑写成了0x $0替换结果就变成了0x A1多了一个空格复制到代码里编译器会直接报错。提示替换前记得把查找模式选成正则表达式而不是普通或扩展。我见过不少新手卡在第一步就是因为忘了切模式结果\b被当成普通字符去找自然什么都搜不到。这个设置位于替换面板左下方的搜索模式单选区域。3. 实测操作三个最常见的批量加前缀场景理论说完了下面用三个真实场景完整走一遍操作流程。每一个场景我都给你列出具体的查找串和替换串可以直接复制粘贴使用不需要自己再去琢磨正则写没写对。3.1 场景一整份文件里散落的十六进制数一次性全部加上前缀假设你有一份系统导出的设备配置信息里面有寄存器名、配置项和若干个裸十六进制数值混杂在同一条记录里。比如uart_baud 258 gpio_mode 1C spi_clk 0F dma_flag 3A目标效果是把所有裸十六进制数统一成带0x前缀uart_baud 258 // 注意这个258是十进制不应该被替换 gpio_mode 0x1C spi_clk 0x0F dma_flag 0x3A操作步骤按Ctrl H打开替换对话框。查找模式选择正则表达式。查找目标输入\b[0-9A-Fa-f]\b替换为输入0x$0点击全部替换。这里有个细节值得说明258按说也是合法十六进制数字258在十六进制里完全成立正则照样会命中它。所以在执行这步操作之前你需要仔细核对哪些数据该加前缀、哪些数据不能动。如果你能确认文件里所有的疑似十六进制数其实都是需要加前缀的那就直接全量替换干脆利落。如果混有十进制数字那就得靠更精确的匹配条件来限定这个放到后面第4节的避坑部分展开。替换完成以后结果会变成uart_baud 258 gpio_mode 0x1C spi_clk 0x0F dma_flag 0x3A注意到没有258原封不动因为它虽然在正则上有资格被匹配但实际经我确认以后不属于目标数据时我就得提前规避。本场景中目标是全部十六进制数那就不用顾虑直接替换即可。实际操作中拿不准的内容建议先点查找下一个逐个过一遍不要上来就全部替换等确认没有异常再批量操作这个习惯能帮你躲掉大量麻烦。3.2 场景二一批紧凑排列的十六进制字节序列统一转为C风格嵌入式开发和协议日志分析中更常见的情况是数据以字节流形式连在一起比如设备返回的射频参数AA BB CC 0D 12 34 5F 6A或者干脆没有空格AABBCC0D12345F6A对于带空格的第一种你只需要用场景一的替换规则\b[0-9A-Fa-f]\b就能把AA、BB、CC这些独立数字全部加前缀。替换结果干净整齐0xAA 0xBB 0xCC 0x0D 0x12 0x34 0x5F 0x6A但是对于没有空格的连续字符串AABBCC0D12345F6A简单加\b就不会得到你想要的效果。因为AABBCC0D12345F6A在正则引擎眼里是一个完整的连续十六进制串\b只会出现在它的开头和结尾于是整串会被当成一个数字替换结果变成0xAABBCC0D12345F6A这显然不是你想要的每个字节一个0x。这种场合就需要先把连续的十六进制字符串按固定长度拆开比如每两个字符一组。思路是这样先用一个替换操作在每个字符对后面插入一个分隔符再执行场景一的替换。两步操作第一步查找目标([0-9A-Fa-f]{2})(?[0-9A-Fa-f])替换为$1,这一步的含义是匹配两个十六进制字符且这两个字符的后面还跟着另一个十六进制字符这个(?...)是正向预查意思是在这个位置之后必须跟着……。替换为$1,表示保留匹配到的两位数字并在其后加一个逗号。执行完后AABBCC0D12345F6A会变成AA,BB,CC,0D,12,34,5F,6A,注意末尾会多一个逗号因为6A后面没有十六进制字符了正向预查不成立所以最后一截不会被替换。你手动删一下末尾逗号或者直接在第二步替换时顺带处理。第二步再对逗号分隔后的数字执行\b[0-9A-Fa-f]\b替换为0x$0结果就是0xAA,0xBB,0xCC,0x0D,0x12,0x34,0x5F,0x6A,如果你的目标格式是C语言数组初始化列表这种输出正好可以直接粘贴使用改个逗号风格就行。我希望你把思路也记下来先结构化为分隔状态再批量加前缀这个套路特别通用。比如以后遇到DEADBEEF这种十六进制字符串要拆成0xDE 0xAD 0xBE 0xEF一个道理。3.3 场景三加前缀的同时统一大小写现实工作中还有一个高频需求文档里的十六进制数五花八门既有大写A1又有小写a1但你要交付的C代码风格要求一律小写字母、前缀统一0x。Notepad 的替换功能可以在加前缀的同时处理大小写。先给个结论直接在替换框里用$0无法同时做大小写转换因为$0是原样内容。但你可以换个思路先把所有十六进制数字统一替换成小写形式再补0x前缀。在 Notepad 中要实现把匹配内容转成小写再用于替换并没有直接的语法支持不像某些编辑器支持\L\1这种转写标记。比较简单的做法是分两步第一步把所有十六进制字符转成小写。查找目标\b[0-9A-Fa-f]\b这个查找目标本身不能直接把内容变小写因为替换框没有大小写转换内置格式。但是 Notepad 有一个隐藏小技巧你可以在替换面板底部用\L前缀结合捕获组来处理。实际操作里更可靠的方法是把替换串写成\begin{...}不不这行是伪代码我重说。Notepad 的 Boost 正则引擎支持\L、\U、\E这些转义指令。所以查找目标保留捕获组写法\b([0-9A-Fa-f])\b替换为\L$1这样匹配到的A1就会变成a1。你点全部替换后文件里所有十六进制数字统一变成了小写。然后再做一次前缀替换\b[0-9a-f]\b替换为0x$0最终结果就是干净整齐的0xa1风格。如果你想要全大写风格那就是\U$1替换成0x$0之外再整体调整。这套先统一大小写再加前缀的流程虽然多一步但胜在稳定而且不容易出错。注意\L$1在某些旧版本 Notepad 上可能不生效建议在做这一步之前先把 Notepad 升级到较新版本否则正则引擎版本不同会造成结果不一致。我最早用的一个老版本\L指令完全无效折腾了半天才意识到是版本问题。4. 最容易翻车的三个场景及完整的排查链路正则替换这项工作大部分时间不是写不出来而是匹配结果跟预期不一致。下面三个问题是我在实际使用中遇到最多的每个我都记录了从发现异常到定位原因的完整过程这样以后你遇到类似情况可以顺着同样的思路去排查。4.1 场景文件里混有MAC地址或包含字母的单词误匹配严重现象表现某次在处理一个包含网卡信息的数据表时执行完替换后发现MAC地址整段都变得乱七八糟甚至普通文字里凡是包含A-F字母的单词都被加上了0x前缀。整个文件几乎没法看。排查过程梳理第一步观察具体替换结果。发现MAC这个词变成了0xMACDEAL变成了0xDEAL。这说明正则\b[0-9A-Fa-f]\b把连续字母MAC中的AC、DEAL中的DEA等片段误判成了十六进制数。原因很清楚A-F字母属于常规英文字母单词边界无法区分这是英文单词的一部分还是独立的十六进制数字。第二步考虑改进匹配规则。为了只匹配十六进制数字而不是英文单词需要引入一个前提条件十六进制数字的右侧不应该紧跟英文字母。于是查找目标改为[0-9A-Fa-f](?!\w)(?!\w)表示右边不能有字母数字下划线。这样MAC中的AC后面跟的是C的下一个字符A等等MAC里匹配到AC时位置在C后面是结束那还是会匹配所以需要连左边也限制。更进一步改成(?![0-9A-Fa-f])[0-9A-Fa-f](?!\w)(?![0-9A-Fa-f])是负向后顾断言表示匹配内容前面不能是十六进制字符。这个写法的语义变成一个完整的、前后都不是十六进制字符的十六进制串它不会匹配英文单词MAC因为MAC整个词的构成是三个十六进制字符连续既能被匹配为MAC的整个串前后边界是单词边界但这个串本质上还是十六进制字符组成所以仍然会被认为是一个十六进制数。要彻底避开英文单词唯一的办法是从上下文语义上判断这超出了正则在纯文本层面能做的范围。实际项目中如果你的数据文件里根本没有自然语言单词用\b[0-9A-Fa-f]\b没有任何问题如果文件里混合了英文文本和十六进制数据那就只能逐条确认或者把需要处理的数据单独复制出来处理完再贴回去。第三步定位结论。这种翻车不是正则语法错了而是匹配条件从语义上无法区分十六进制数和英文单词。理解到这一点你就知道没有一个正则能完美解决所有场景关键在于操作前对文件内容做一次准确的是否纯净预判。我现在的习惯是在处理任何数据文件之前先花十秒钟用查找功能跑一遍[0-9A-Fa-f]看看到底有多少内容是我不想碰的再决定用哪种边界条件。4.2 场景连续替换两次后同一批数字多了一倍前缀现象表现第一次执行全部替换成功所有数字都变成了0x前缀。但手一滑又按了一次替换快捷键结果前缀多了一层变成了0x0x1C。排查过程梳理这个现象的原理很简单执行完第一次替换后文件内容已经变了。原来裸的1C变成了0x1C。如果你不修改查找目标再执行一次替换正则引擎会重新扫描全文发现新的0x1C中1C仍然满足\b[0-9A-Fa-f]\b的匹配条件于是又给它加上一层前缀产生0x0x1C。更微妙的是第二次执行时匹配到的其实是0x1C里的1C所以它不是给0x1C这个整体加前缀而是给其中1C部分加生成的结果就是0x0x1C。解决办法有几个替换前养成好习惯先把查找下一个点一遍确认当前状态下已经不存在裸的十六进制数字再执行替换。如果你要处理的文件本身已经有一部分带0x前缀的数字一部分不带前缀的数字那么简单的\b[0-9A-Fa-f]\b会把带前缀的0x1C里的1C也再换一次同样出现问题。这种情况需要把查找目标写成不能是0x后面紧跟十六进制字符用负向后顾(?!0x)\b[0-9A-Fa-f]\b这里(?!0x)表示匹配位置前面不能是0x这样已经带前缀的数字就不会被二次匹配同一文本可以安全反复执行多次替换直到所有裸数字都加上前缀。你可能会问(?!0x)\b[0-9A-Fa-f]\b里\b和(?!0x)的关系会不会冲突实践后发现不会。\b是界定数字是否独立成词(?!0x)是确保它前头没有0x字样各自管各自的条件组合起来就是一个没有前缀的独立十六进制数。这个重复执行导致重复替换的坑是所有文本批量处理新手必踩的建议直接在操作上形成条件反射任何时候点击全部替换之前先扫一眼查找目标和当前文件的状态是否匹配。4.3 场景替换完后才发现数字后面紧跟的字母也被吃掉了现象表现执行完替换后发现2C0FF变成了0x2C0F后面那个F不见了。或者12AB变成了0x12AB倒是没事但某些特定位置就是少一位。排查过程梳理这个现象往往不是正则写错而是预查写错了。在场景二的连续字节拆分中我用了正向预查(?[0-9A-Fa-f])来保证只有后面还有十六进制字符的两位数字才插入逗号。如果你在拆分步骤把预查条件误写成了匹配型捕获就会出现吃掉字符的情况。举个例子如果你把拆分替换写成([0-9A-Fa-f]{2})([0-9A-Fa-f])替换为$1,这时候匹配的是两位数字加一位数字共三位替换结果是只保留前两位加逗号第三位就被丢弃了。连续执行下来第一组拆掉以后第二组从第三位开始重新匹配遇到奇数个字符时末尾会丢数据。这就像你每数两只羊就赶走一只数到最后羊就少了。排查这类问题最高效的验证方式是最小化实验复制一小段典型数据比如AABBCC用当前正则执行一次替换人工检查结果是否符合预期。如果AABBCC变成AA,BB,而不是AA,BB,CC,那就说明捕获组写多了。正则调试时别直接在几千行的大文件上做实验那是折腾自己。我日常的做法是先在 Notepad 里新建一个临时文档粘贴5到10组具有代表性的数据进行验证确认无误后再对着真实文件执行全部替换。别小看这30秒钟的验证它能避免你在真实数据上搞出不可逆的破坏。虽然 Notepad 有撤销功能但万一你替换完又做了其他操作撤销栈被冲掉那就真不好恢复了。5. 反向操作批量去掉0x前缀的几种方案加前缀是刚需去掉前缀同样是刚需。有时候你从某个自动生成工具里拿到的C代码变量定义全是0xFF风格可手头的比对脚本只接受不带前缀的裸十六进制或者你要把数据粘贴进某些只认原始格式的表格工具这时候就需要批量去掉所有0x前缀。5.1 最简单粗暴方案直接替换字符串查找目标0x替换为留空点击全部替换。一瞬间所有0x前缀全部消失。这个方案唯一的风险是如果文件里除了十六进制数字的0x前缀以外还有其他人写的字符串、注释、变量名中恰好包含0x字样那也会被一并清掉。比如某行注释写着此处参考 ARM 手册 0x 系列说明——这种注释里的0x也会被吞掉导致注释语义改变。所以我强烈建议使用直接替换字符串这个方案前先想清楚文件里0x出现的所有位置是否都符合你的清理预期。如果文件来源单一、格式规整这个方案最快最省事如果文件来源混杂就要用稍微复杂但更安全的正则方案。5.2 精确方案只处理十六进制数字前置的0x查找目标\b0[xX]([0-9A-Fa-f])\b替换为$1这个正则会匹配0xFF、0xFF、0XFF等多种写法并且只保留后面的十六进制数字本体前缀的0x被摘除其余地方出现的0x字样不受影响。用这个方案上面提到的那种注释里的0x不会被动到一丝一毫。这种只处理符合格式的内容、不碰其他文本的安全感在处理大型工程文件时特别重要。如果你还要同时保留大小写信息那直接让$1原样输出就行。如果想去掉前缀的同时把小写ff转成大写的FF可以配合\U做大写转换具体写法和前面加前缀时的小写转换逻辑一致。5.3 批量替换0X大写前缀为小写0x有时候你接手别人的代码里面前缀五花八门有些是0X。想统一成0x查找目标设为0X(?[0-9A-Fa-f])替换为0x这样就只把大写X前缀换成小写x且仅限于后面紧跟十六进制字符的0X不会影响其他写法。5.4 利用替换正则实现前缀规范化全流程如果你想一次性完成所有数字统一为小写、前缀统一为小写0x可以分两步操作第一步0X统一成0x用上面的规则。第二步对所有满足\b0x[0-9A-Fa-f]\b的内容用\L$0转成小写。这里$0指代整个匹配内容也就是0xFF变成0xff。最终你就会得到一整份风格统一、干净利落的十六进制数据块。这类规范化操作在向同事交付代码或提交到公共代码库之前特别有用能省去后续审查人员一堆不必要的格式纠结。6. 正则之外的配合技巧把替换结果变成可用的C数组或Python列表仅靠替换框你已经能完成大部分十六进制数据整理工作。但如果你经常需要把一整段设备日志转成可编译的C数组定义或者转成Python字节序列还有几个配合技巧让这个流程更丝滑。6.1 通过处理-多行粘贴直接生成C数组先看原始数据AA BB CC DD EE FF 01 02 03 04按前面场景二的办法加好前缀得到一行式的0xAA 0xBB 0xCC 0xDD 0xEE 0xFF 0x01 0x02 0x03 0x04。但C语言数组通常写成多行带逗号的形式每条一两个字节比较常见。你可以再执行一次替换把空格替换成逗号加换行查找目标这里输入一个空格替换为,\r\n替换后内容会变成0xAA, 0xBB, 0xCC, ...直接把这些粘到unsigned char buf[] { ... };的大括号里即可编译。如果目标格式是每个数字中间加逗号、末尾不加那就手动删一下最后一个逗号或者再补一步正则处理。6.2 用标记全部快速检查是否还有漏网之数在替换完成之后习惯性按Ctrl M调出标记功能也可以但更常用的方法是把查找目标设为\b[0-9A-Fa-f]\b勾选查找全部下面的标记选项所有满足条件的数字会在文档里高亮显示。你扫一眼高亮区域如果全部都是已经带0x的内容那就说明替换彻底干净了。如果还有个别裸数字高亮会非常直观地暴露出来可以再多执行一次替换或者逐个检查。这个替换后复查步骤看起来多余实际上能救你不少次。曾经我处理一份三百行的配置导出文件眼睛扫过以为全部替换成功了结果写入编译环境后报错一查是某一行行尾有一个奇怪的B没加前缀。从那以后每次批量替换完我都会强制自己用高亮复查一遍花不到10秒但省下的排查时间以小时计。6.3 在多次操作场景下使用宏录制如果你每周都要处理同一类的十六进制数据从去前缀到加前缀再到大小写统一包含多步替换不妨把这些步骤录制成一个 Notepad 宏。用插件或直接录制都可以。这样以后打开文件按一下热键所有步骤自动执行真正实现一键整理十六进制数据。宏录制时要注意录制过程中不要手动点选文件内容否则宏会把鼠标精确位置也录进去切换到新文件时容易出问题。只录制纯粹的快捷键操作比如打开替换对话框、输入查找串、点全部替换这样的宏在不同文件之间才具备通用性。我录过一个三步骤宏从裸数据到带前缀小写再到生成多行C数组整个过程按一下热键几十秒人工活变成一秒钟自动化体验非常爽。6.4 Notepad 之外的替代方案比较有一定经验的用户可能会问为啥非要用 NotepadVim 里一条:%s/\[0-9a-fA-F]\\/0x/g不也一样确实是Vim、Sublime Text、VS Code 等主流编辑器都能完成这个任务。但 Notepad 的优势在于轻量、启动快、正则替换界面直观对于非程序员背景或者偶尔处理数据的办公人员来说学习成本最低。不需要记命令行指令不需要装扩展插件打开就干。如果是处理海量数据文件几万行起步Notepad 也完全扛得住。我实测过一份包含三万个十六进制数值的日志文件一次全部替换耗时在1秒左右体验很流畅。当然如果你的数据规模到百万级、千万级那就不是文本编辑器的范畴了应该考虑用 Python 脚本或者其他更专业的批处理工具。