搜索非ascii字符

时间:2015-04-13 07:58:10

标签: linux unicode grep

我有一个文件,a.out,其中包含许多行。每行只有一个字符,可以是unicode字符U+2013,也可以是小写字母a-z

在a.out上执行文件命令会引出结果UTF-8 Unicode文本。

locale命令报告:

LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

如果我发出命令grep -P -n "[^\x00-\xFF]" a.out,我希望只返回包含U+2013的行。如果我在cygwin下进行测试就是这种情况。然而,问题环境是Oracle Linux Server 6.5版,问题是grep命令不返回任何行。如果我发出grep -P -n "[\x00-\xFF]" a.out然后返回所有行。

我意识到" [grep -P] ...是高度实验性的,grep -P可能会警告未实现的功能。"但没有发出警告。

我错过了什么吗?

3 个答案:

答案 0 :(得分:3)

我建议避免使用狡猾的grep -P实现并使用真实的东西。这有效:

perl -CSD -nle 'print "$.: $_" if /\P{ASCII}/' utfile1 utfile2 utfile3 ...

其中:

  • -CSD选项表示stdio trio(stdin,stdout,stderr)和磁盘文件都应视为UTF-8编码。

  • $.代表当前记录(行)编号。

  • $_代表当前行。

  • \P{ASCII}匹配 ASCII的任何代码点。

答案 1 :(得分:0)

How Do I grep For all non-ASCII Characters in UNIX中的评论给出了答案:

  

Grep(和系列)不进行Unicode处理,将多字节字符合并为单个实体,以便进行正则表达式匹配。

这意味着U+20130xe20x800x93)的UTF-8编码不被grep视为单个可打印字符的一部分给定范围。

GNU grep手册的d escription of -P未提及Unicode或UTF-8。相反,它说将模式解释为Perl正则表达式。(这并不意味着结果与Perl的相同,只是某些反斜杠转义< EM>类似)。

Perl本身可以告知使用UTF-8编码。但是,Filtering invalid utf8中使用Perl的示例不使用该功能。相反,表达式(如问题grep中的表达式)仅测试单个字节 - 而不是完整字符。

答案 2 :(得分:0)

gawk可以帮助您解决这个问题,

这是awk one-liner:

 awk -v FS="" 'BEGIN{for(i=1;i<128;i++)ord[sprintf("%c",i)]=i}
               {for(i=1;i<=NF;i++)if(!($i in ord))print $i}' file

下面是gawk的测试:

kent$  cat f
abcd
+ß
s+äö
ö--我
中文

kent$  awk -v FS="" 'BEGIN{for(i=1;i<128;i++)ord[sprintf("%c",i)]=i}{for(i=1;i<=NF;i++)if(!($i in ord))print $i}' f
ß
ä
ö
ö
我
中
文