如何使用sed捕获组直接输出转译后的十六进制值?
解决sed捕获组构造十六进制转义的问题
嘿,我完全懂你碰到的这个sed坑!当你直接写\x3A的时候,sed能乖乖把它转成冒号,但一旦想用捕获组\1拼接成\x\1,它就只会输出x加上捕获到的内容,根本不会把这俩组合起来解析成十六进制字符。
这背后的原因其实是sed处理替换字符串的顺序:它会先解析所有固定的转义序列(比如\x),然后才会替换捕获组的内容。所以\x\1在sed眼里就是“转义x”加上\1的内容,而不是“把\1的内容当成十六进制来转义”。
下面给你几个靠谱的解决办法:
方法1:用GNU sed的e命令借力shell
如果你用的是GNU sed(大部分Linux系统默认都是),可以用e标志让sed把替换后的内容当成shell命令执行,让shell帮我们解析十六进制:
echo bbb%3Accc | sed 's/%\([A-Fa-f0-9]\{2\}\)/printf "\\x\1"/e'
简单说下逻辑:
- 先匹配
%后面跟着两位十六进制字符的片段 - 把这段替换成
printf "\\x\1",\1就是捕获到的那两位十六进制值 e标志会让sed执行这个printf命令,printf会把\x+十六进制值转成对应的ASCII字符- 最终就能输出
bbb:ccc啦
方法2:用awk灵活处理
awk的字符串处理能力比sed强不少,可以直接把十六进制转成十进制再转成字符:
echo bbb%3Accc | awk '{while(match($0,/%([A-Fa-f0-9]{2})/,arr)) { char = sprintf("%c", strtonum("0x" arr[1])) $0 = substr($0,1,RSTART-1) char substr($0,RSTART+RLENGTH) }}1'
这个脚本会循环查找所有符合%XX格式的URL编码,把每个都转换成对应的ASCII字符,最后输出处理后的字符串。
方法3:用Perl(如果系统装了的话)
Perl的正则替换直接支持这种动态转义,写法超简洁:
echo bbb%3Accc | perl -pe 's/%([A-Fa-f0-9]{2})/chr(hex($1))/ge'
这里hex($1)把捕获到的十六进制字符串转成十进制数字,chr()再把数字转成对应的字符,g标志表示替换所有匹配的部分,一步到位。
总之呢,sed本身的替换机制不支持动态解析\x加捕获组的转义,所以得借助外部命令或者更强大的文本工具来实现这个需求~
内容的提问来源于stack exchange,提问作者one-liner
相关产品推荐
相关产品推荐

