我有几个非常大的XML文件,我试图找到包含非ascii字符的行。我试过以下几种方法:

grep -e "[\x{00FF}-\x{FFFF}]" file.xml

但是这将返回文件中的每一行,而不管该行是否包含指定范围内的字符。

是我的语法错误还是我做错了什么?我也试过:

egrep "[\x{00FF}-\x{FFFF}]" file.xml 

(在模式周围使用单引号和双引号)。


当前回答

在perl中

perl -ane '{ if(m/[[:^ascii:]]/) { print  } }' fileName > newFile

其他回答

查找所有非ascii字符会给人留下这样的印象:要么查找unicode字符串,要么打算单独剥离这些字符。

对于前者,可以尝试其中一个(变量文件用于自动化):

 file=file.txt ; LC_ALL=C grep -Piao '[\x80-\xFF\x20]{7,}' $file | iconv -f $(uchardet $file) -t utf-8

 file=file.txt ; pcregrep -iao '[\x80-\xFF\x20]{7,}' $file | iconv -f $(uchardet $file) -t utf-8

 file=file.txt ; pcregrep -iao '[^\x00-\x19\x21-\x7F]{7,}' $file | iconv -f $(uchardet $file) -t utf-8

如前面的答案所述,如果没有LC_ALL=C, Vanilla grep将无法正常工作。

ASCII范围是x00-x7F,空格是x20,因为字符串有空格,所以负范围省略了它。

非ascii范围是x80-xFF,因为字符串有空格,所以正范围加上它。

String假定在范围内至少有7个连续字符。{7}。

对于shell可读输出,uchardet $file返回文件编码的猜测值,该值被传递给iconv进行自动插值。

不像上面大多数解决方案那样对非ASCII字符的字节范围进行假设,在我看来,明确ASCII字符的实际字节范围会稍微好一些。

所以第一个解决方案是:

grep --color='auto' -P -n '[^\x00-\x7F]' file.xml

(基本上greps十六进制ASCII范围以外的任何字符:从\x00到\x7F)

在Mountain Lion上,这将无法工作(由于BSD grep中缺乏PCRE支持),但通过Homebrew安装PCRE,以下将同样工作:

pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml

大家能想到什么优点或缺点吗?

最简单的方法是定义一个非ascii字符…作为非ASCII字符的字符。

LC_ALL=C grep '[^ -~]' file.xml

如果需要,在^后面添加一个制表符。

设置LC_COLLATE=C可以避免在许多地区中出现关于字符范围含义的令人讨厌的意外。必须设置LC_CTYPE=C以匹配单字节字符-否则该命令将错过当前编码中的无效字节序列。设置LC_ALL=C可以完全避免语言环境相关的影响。

以下是我的工作:

grep -P "[\x80-\xFF]" file.xml

非ascii字符从0x80开始,在查看字节时转到0xFF。Grep(和家族)不做Unicode处理,将多字节字符合并为一个实体,以便进行正则表达式匹配。我的grep中的-P选项允许在字符类中使用\xdd转义来实现您想要的效果。

下面的代码工作:

find /tmp | perl -ne 'print if /[^[:ascii:]]/'

将/tmp替换为要搜索的目录名。