为何Sed的点号无法匹配latin1编码中的ù字符?
Latin1编码文件与Sed匹配异常问题
我有两个内容都是aùb的文件:
critic_utf8:采用UTF-8编码critic_latin1:采用Latin1编码
用od -a命令查看它们的字节结构,输出如下:
$ od -a critic_utf8 0000000 a C 9 b nl 0000005 $ od -a critic_latin1 0000000 a y b nl 0000004
子问题:critic_latin1输出里的y是什么?
这里的y是od -a对Latin1编码下ù对应字节(十六进制0xF9)的ASCII别名映射。od -a会把非标准ASCII字节转换成易读的近似字符别名,0xF9在这个规则里就被显示成y,它本质就是Latin1编码中表示ù的单字节值。
Sed匹配异常的原因
测试发现Sed的.元字符匹配不了critic_latin1里的ù:
$ sed 's/.*/x/' critic_latin1 xùb $ sed 's/.*/x/' critic_utf8 x $ sed 's/./x/g' critic_latin1 xùx $ sed 's/./x/g' critic_utf8 xxx
就算加了-z选项(让输入以NUL分隔,.可匹配换行符),结果还是不对:
$ sed -z 's/.*/x/' critic_latin1 xùb
这不是Sed处理不了Latin1文件,而是传统Sed是基于单字节ASCII设计的:
- 默认情况下,Sed的
.只能匹配ASCII范围内的单字节(字节值0x01到0x7F),而Latin1的ù对应字节是0xF9,属于ASCII扩展区间(0x80-0xFF),不在默认匹配范围内。 - UTF-8编码的
ù是两个字节(0xC3和0xB9,对应od -a里的C和9),这两个字节都在ASCII的映射范围内,所以能被.正常匹配。
如果要让Sed正确处理Latin1这类扩展ASCII编码,要么用支持多字节字符的Sed版本(比如GNU Sed),要么设置对应的环境变量,比如LC_CTYPE=iso-8859-1 sed ...,让Sed识别扩展ASCII字节为可匹配字符。
问题场景
我是在处理存储单词和同义词的*.idx与*.dat文件时碰到这个问题的,当时正在尝试实践某Stack Overflow回答里的操作方法。
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

