我有一个带有两个非ascii字节(0xFF和0xFE)的文本文件:
??58832520.3,ABC
348384,DEF
此文件的十六进制是:
FF FE 35 38 38 33 32 35 32 30 2E 33 2C 41 42 43 0A 33 34 38 33 38 34 2C 44 45 46
巧合的是,FF和FE恰好是前导字节(它们存在于我的文件中,尽管看起来总是在一行的开头)。
我试图用sed去掉这些字节,但我做的事似乎与它们不匹配。
$ sed 's/[^a-zA-Z0-9\,]//g' test.csv
??588325203,ABC
348384,DEF
$ sed 's/[a-zA-Z0-9\,]//g' test.csv
??.
主要问题:如何删除这些字节?
额外问题:上面的两个正则表达式是直接否定,所以其中一个逻辑上必须过滤掉这些字节,对吧?为什么这两个正则表达式都匹配0xFF和0xFE字节?
更新:剥离一系列十六进制字节的直接方法(由下面两个答案建议)似乎从每一行中删除第一个“合法”字节并留下字节我是试图摆脱:
$sed 's/[\x80-\xff]//' test.csv
??8832520.3,ABC
48384,DEF
FF FE 38 38 33 32 35 32 30 2E 33 2C 41 42 43 0A 34 38 33 38 34 2C 44 45 46 0A
注意每行开头缺少“5”和“3”,新的0A添加到文件末尾。
更大的更新:此问题似乎是系统特定的。在OSX上观察到了这个问题,但是建议(包括我上面的原始sed语句)的工作正如我在NetBSD上预期的那样。
解决方案:通过Perl,同样的任务看起来很容易:
$ perl -pe 's/^\xFF\xFE//' test.csv
58832520.3,ABC
348384,DEF
但是,我会将此问题保持开放,因为这只是一种解决方法,并不能解释sed的问题。
答案 0 :(得分:4)
sed 's/[^ -~]//g'
或另一个答案暗示
sed 's/[\x80-\xff]//g'
请参阅sed信息页面的section 3.9。题为“逃避”的章节。
OSX的编辑,原生lang设置为en_US.UTF-8
尝试
LANG='' sed 's/[^ -~]//g' myfile
这适用于这里的osx机器,我不完全确定为什么它在UTF-8中不起作用
答案 1 :(得分:3)
这将删除所有以特定字节FF FE
开头的行sed -e 's/\xff\xfe//g' hexquestion.txt
你的否定正则表达式不起作用的原因是[]指定了一个字符类。 sed假设一个特定的字符集,可能是ascii。你文件中的这些字符不是7位ascii字符,因为它们都以F开头.sed不知道如何处理这些字符。上面的解决方案不使用字符类,因此它应该在平台和字符集之间更容易移植。
答案 2 :(得分:2)
文件开头的FF
和FE
字节称为“字节顺序标记(BOM)”。它可以出现在Unicode文本流的开头,以指示文本的字节顺序。 FF FE
表示Little Endian中的UTF-16
以下是常见问题解答的摘录:
问:我应该如何处理物料清单?答:以下是一些指导原则:
- 特定协议(例如,
.txt
文件的Microsoft约定)可能需要在某些Unicode数据流(例如文件)上使用BOM。如果需要符合此类协议,请使用BOM。- 某些协议允许在未标记文本的情况下使用可选BOM。在那些情况下,
- 如果已知文本数据流是纯文本,但编码未知,则BOM可用作签名。如果没有BOM,则编码可以是任何内容。
- 如果已知文本数据流是纯Unicode文本(但不是哪个字节序),那么BOM可以用作签名。如果没有BOM,则应将文本解释为big-endian。
- 某些面向字节的协议需要文件开头的ASCII字符。如果UTF-8与这些协议一起使用,则应避免使用BOM作为编码形式签名。
- 如果已知数据流的精确类型(例如Unicode big-endian或Unicode little-endian),则不应使用BOM。特别是,无论何时将数据流声明为UTF-16BE,UTF-16LE,UTF-32BE或UTF-32LE,都不得使用BOM。
醇>
答案 3 :(得分:1)
在OS X上,字节顺序标记可能被读作单个单词。根据字节顺序尝试sed 's/^\xfffe//g'
或sed 's/^\xfeff//g'
。
答案 4 :(得分:0)
您可以使用\ xff \ xfE获取十六进制代码,并将其替换为空。
答案 5 :(得分:0)
要表明这不是Unicode BOM的问题,而是8位与7位字符的问题并且与区域设置相关联,请尝试以下方法:
显示所有字节:
$ printf '123 abc\xff\xfe\x7f\x80' | hexdump -C
00000000 31 32 33 20 61 62 63 ff fe 7f 80 |123 abc....|
让sed
删除用户区域设置中不是字母数字的字符。请注意,空格和0x7f已被删除:
$ printf '123 abc\xff\xfe\x7f\x80'|sed 's/[^[:alnum:]]//g' | hexdump -C
00000000 31 32 33 61 62 63 ff fe 80 |123abc...|
让sed
删除C语言环境中不是字母数字的字符。请注意,只剩下“123abc”:
$ printf '123 abc\xff\xfe\x7f\x80'|LANG=C sed 's/[^[:alnum:]]//g' | hexdump -C
00000000 31 32 33 61 62 63 |123abc|
答案 6 :(得分:0)
作为替代方案,您可以使用ed(1):
printf '%s\n' H $'g/[\xff\xfe]/s///g' ',p' | ed -s test.csv
printf '%s\n' H $'g/[\xff\xfe]/s///g' wq | ed -s test.csv # in-place edit