我有几个非常大的XML文件,正在尝试查找包含非ASCII字符的行。我尝试了以下方法:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
但这将返回文件中的每一行,无论该行是否包含指定范围内的字符。
我的语法有误还是做错了其他事情?我也尝试过:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(用单引号和双引号将模式引起来)。
我有几个非常大的XML文件,正在尝试查找包含非ASCII字符的行。我尝试了以下方法:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
但这将返回文件中的每一行,无论该行是否包含指定范围内的字符。
我的语法有误还是做错了其他事情?我也尝试过:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(用单引号和双引号将模式引起来)。
Answers:
您可以使用以下命令:
grep --color='auto' -P -n "[\x80-\xFF]" file.xml
这将为您提供行号,并以红色突出显示非ASCII字符。
在某些系统中,根据您的设置,以上操作将无效,因此您可以按反序进行grep
grep --color='auto' -P -n "[^\x00-\x7F]" file.xml
还要注意,重要的一点是-P
等于的标志--perl-regexp
:因此它将把您的模式解释为Perl正则表达式。它也说
这是高度实验性的,grep -P可能会警告未实现的功能。
grep
(在OS X 10.8 Mountain Lion上)不起作用,因为它不支持该P
选项。
grep
Homebrew的dupes
库中提供了GNU版本(启用可以使用brew tap homebrew/dupes
):brew install grep
dupes
库的一种替代方法是安装pcre
:brew install pcre
...作为此过程的一部分,您将获得该pcregrep
实用程序,您可以按以下方式使用该实用程序:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
brew
用户,可以使用安装GNU的coreutilsbrew install coreutils
。这将为您提供许多以'g'开头的GNU工具-在这种情况下,请使用ggrep
。这应该避免替换系统实用程序引起的问题,因为特定于系统的Mac脚本现在依赖于BSD grep。
ag "[\x80-\xFF]" file
您只需要安装的Mac上运行良好the_silver_searcher
像上面的大多数解决方案一样,与其对非ASCII字符的字节范围进行假设,还不如对ASCII字符的实际字节范围进行明确表示,IMO更好。
因此,第一个解决方案例如将变为:
grep --color='auto' -P -n '[^\x00-\x7F]' file.xml
(基本上,对于十六进制ASCII范围之外的任何字符,它都会陷入混乱:从\ x00到\ x7F)
在不起作用的Mountain Lion上(由于BSD grep中缺少PCRE支持),但pcre
通过Homebrew 进行安装,以下内容同样适用:
pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml
任何人都可以考虑的利弊?
LC_COLLATE=C grep $'[^\1-\177]'
可以使用(适用于无空字节的文件)
以下对我有用:
grep -P "[\x80-\xFF]" file.xml
非ASCII字符从0x80开始,在查看字节时变为0xFF。Grep(和家族)不执行Unicode处理,以将多字节字符合并到单个实体中以进行正则表达式匹配。-P
我的grep中的选项允许\xdd
在字符类中使用转义符来完成所需的操作。
echo '소녀시대' | grep -P "[\x80-\xFF]"
对我没有任何回报-其他人可以确认吗?(GNU grep 2.21)
echo '소녀시대' | grep -P "[^\x00-\x7F]"
。或只使用the_silver_searcher
@slf指出的方式:echo '소녀시대' | ag "[\x80-\xFF]"
最简单的方法是将非ASCII字符定义为不是ASCII字符的字符。
LC_ALL=C grep '[^ -~]' file.xml
^
如有必要,请在之后添加标签。
设置LC_COLLATE=C
可以避免在许多语言环境中对字符范围的含义感到惊讶。LC_CTYPE=C
必须进行设置才能匹配单字节字符-否则该命令将丢失当前编码中的无效字节序列。设置LC_ALL=C
完全避免了依赖语言环境的影响。
echo "A" | LC_COLLATE=C grep '[^ -~]'
是一场比赛
LC_ALL=en_US.UTF-8
,那将胜过LC_COLLATE
设置。您不应该在您的环境中使用它!LC_ALL
通常只是强制特定任务使用特定语言环境C
。要为所有类别设置默认语言环境,请设置LANG
。
LC_ALL=C
,它在Mac OS X和Ubuntu上的行为有所不同。添加此设置后,它们将得到相同的结果。
这是我发现的另一个变体,它与grep搜索所接受的答案产生的结果完全不同[\x80-\xFF]
。也许对找到其他非ASCII字符的人有用:
grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
注意:我的计算机的grep(苹果机)没有此-P
选项,因此我选择了,并brew install grep
使用ggrep
代替进行了上述调用grep
。
搜索不可打印的字符。TLDR;执行摘要
LC_ALL=C
,使grep执行扩展的unicode可能需要的设置因此,首选的非ascii字符查找器:
$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test
如最佳答案中所示,逆grep:
$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test
如最佳答案,但WITH LC_ALL=C
:
$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test
。。更多 。。令人毛骨悚然的细节:。。
我同意上面隐藏在注释中的Harvey的观点,搜索不可打印字符通常更有用,或者当您确实应该考虑不可打印时,可以轻松地考虑使用非ASCII。Harvey建议“使用此:“ [^\n -~]
”。为DOS文本文件添加\ r。这将转换为“ [^\x0A\x020-\x07E]
”,并为CR添加\ x0D“
另外,在搜索不可打印的字符时,向grep添加-c(显示已匹配模式的计数)非常有用,因为匹配的字符串可能会弄乱终端。
我发现将范围0-8和0x0e-0x1f(添加到0x80-0xff范围)是一个有用的模式。这不包括TAB,CR和LF以及一个或两个以上不常见的可打印字符。因此,恕我直言,一个非常有用的(尽管是粗糙的)grep模式是这样的:
grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *
实际上,通常您需要执行以下操作:
LC_ALL=C grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *
分解:
LC_ALL=C - set locale to C, otherwise many extended chars will not match (even though they look like they are encoded > 0x80)
\x00-\x08 - non-printable control chars 0 - 7 decimal
\x0E-\x1F - more non-printable control chars 14 - 31 decimal
\x80-1xFF - non-printable chars > 128 decimal
-c - print count of matching lines instead of lines
-P - perl style regexps
Instead of -c you may prefer to use -n (and optionally -b) or -l
-n, --line-number
-b, --byte-offset
-l, --files-with-matches
例如,使用find的实际示例grep grep当前目录下的所有文件:
LC_ALL=C find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} +
您可能希望有时调整grep。例如,在某些可打印文件中使用的BS(0x08-退格键)字符或排除VT(0x0B-垂直制表符)。在某些情况下,BEL(0x07)和ESC(0x1B)字符也可以视为可打印的。
Non-Printable ASCII Chars ** marks PRINTABLE but CONTROL chars that is useful to exclude sometimes Dec Hex Ctrl Char description Dec Hex Ctrl Char description 0 00 ^@ NULL 16 10 ^P DATA LINK ESCAPE (DLE) 1 01 ^A START OF HEADING (SOH) 17 11 ^Q DEVICE CONTROL 1 (DC1) 2 02 ^B START OF TEXT (STX) 18 12 ^R DEVICE CONTROL 2 (DC2) 3 03 ^C END OF TEXT (ETX) 19 13 ^S DEVICE CONTROL 3 (DC3) 4 04 ^D END OF TRANSMISSION (EOT) 20 14 ^T DEVICE CONTROL 4 (DC4) 5 05 ^E END OF QUERY (ENQ) 21 15 ^U NEGATIVE ACKNOWLEDGEMENT (NAK) 6 06 ^F ACKNOWLEDGE (ACK) 22 16 ^V SYNCHRONIZE (SYN) 7 07 ^G BEEP (BEL) 23 17 ^W END OF TRANSMISSION BLOCK (ETB) 8 08 ^H BACKSPACE (BS)** 24 18 ^X CANCEL (CAN) 9 09 ^I HORIZONTAL TAB (HT)** 25 19 ^Y END OF MEDIUM (EM) 10 0A ^J LINE FEED (LF)** 26 1A ^Z SUBSTITUTE (SUB) 11 0B ^K VERTICAL TAB (VT)** 27 1B ^[ ESCAPE (ESC) 12 0C ^L FF (FORM FEED)** 28 1C ^\ FILE SEPARATOR (FS) RIGHT ARROW 13 0D ^M CR (CARRIAGE RETURN)** 29 1D ^] GROUP SEPARATOR (GS) LEFT ARROW 14 0E ^N SO (SHIFT OUT) 30 1E ^^ RECORD SEPARATOR (RS) UP ARROW 15 0F ^O SI (SHIFT IN) 31 1F ^_ UNIT SEPARATOR (US) DOWN ARROW
更新:我最近不得不重新审视它。并且,YYMV取决于终端设置/太阳能天气预报BUT。。我注意到grep找不到很多unicode或扩展字符。即使从直觉上来说,它们应该匹配0x80到0xff的范围,但3和4字节的unicode字符却不匹配。??? 谁能解释一下?是。@frabjous询问和@calandoa解释说,LC_ALL=C
应使用该命令来设置使grep匹配的命令的语言环境。
例如我的语言环境为LC_ALL=
空
$ locale
LANG=en_IE.UTF-8
LC_CTYPE="en_IE.UTF-8"
.
.
LC_ALL=
具有LC_ALL=
空匹配的grep 匹配2字节编码的char,但不匹配3和4字节编码的char:
$ grep -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" notes_unicode_emoji_test
5:© copyright c2a9
7:call underscore c2a0
9:CTRL
31:5 © copyright
32:7 call underscore
grep with LC_ALL=C
确实与您想要的所有扩展字符匹配:
$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test
1:���� unicode dashes e28090
3:��� Heart With Arrow Emoji - Emojipedia == UTF8? f09f9298
5:� copyright c2a9
7:call� underscore c2a0
11:LIVE��E! ���������� ���� ���������� ���� �� �� ���� ���� YEOW, mix of japanese and chars from other e38182 e38184 . . e0a487
29:1 ���� unicode dashes
30:3 ��� Heart With Arrow Emoji - Emojipedia == UTF8 e28090
31:5 � copyright
32:7 call� underscore
33:11 LIVE��E! ���������� ���� ���������� ���� �� �� ���� ���� YEOW, mix of japanese and chars from other
34:52 LIVE��E! ���������� ���� ���������� ���� �� �� ���� ���� YEOW, mix of japanese and chars from other
81:LIVE��E! ���������� ���� ���������� ���� �� �� ���� ���� YEOW, mix of japanese and chars from other
这个perl匹配项(部分在stackoverflow上的其他地方找到)或最上面答案的反grep似乎确实找到了所有〜weird〜和〜wonderful〜“ non-ascii”字符而未设置语言环境:
$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test
$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test
1 ‐‐ unicode dashes e28090
3 💘 Heart With Arrow Emoji - Emojipedia == UTF8? f09f9298
5 © copyright c2a9
7 call underscore c2a0
9 CTRL-H CHARS URK URK URK
11 LIVE‐E! あいうえお かが アイウエオ カガ ᚊ ᚋ ซฌ आइ YEOW, mix of japanese and chars from other e38182 e38184 . . e0a487
29 1 ‐‐ unicode dashes
30 3 💘 Heart With Arrow Emoji - Emojipedia == UTF8 e28090
31 5 © copyright
32 7 call underscore
33 11 LIVE‐E! あいうえお かが アイウエオ カガ ᚊ ᚋ ซฌ आइ YEOW, mix of japanese and chars from other
34 52 LIVE‐E! あいうえお かが アイウエオ カガ ᚊ ᚋ ซฌ आइ YEOW, mix of japanese and chars from other
73 LIVE‐E! あいうえお かが アイウエオ カガ ᚊ ᚋ ซฌ आइ YEOW, mix of japanese and chars from other
因此,首选的非ascii字符查找器:
$ perl -ne 'print "$. $_" if m/[\x00-\x08\x0E-\x1F\x80-\xFF]/' notes_unicode_emoji_test
如最佳答案中所示,逆grep:
$ grep --color='auto' -P -n "[^\x00-\x7F]" notes_unicode_emoji_test
如最佳答案,但WITH LC_ALL=C
:
$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test
奇怪的是,我今天必须这样做!我最终使用Perl是因为我无法使grep / egrep正常工作(即使在-P模式下也是如此)。就像是:
cat blah | perl -en '/\xCA\xFE\xBA\xBE/ && print "found"'
对于unicode字符(\u2212
例如下面的示例),请使用以下命令:
find . ... -exec perl -CA -e '$ARGV = @ARGV[0]; open IN, $ARGV; binmode(IN, ":utf8"); binmode(STDOUT, ":utf8"); while (<IN>) { next unless /\N{U+2212}/; print "$ARGV: $&: $_"; exit }' '{}' \;
查找所有非ASCII字符给人的印象是,要么正在寻找Unicode字符串,要么打算单独剥离所述字符。
对于前者,请尝试以下方法之一(变量file
用于自动化):
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,香草grep将无法正常工作。
ASCII范围为x00-x7F
,空格为x20
,因为字符串的空格为负范围,则忽略它。
非ASCII范围是x80-xFF
,因为字符串之间有空格,所以正范围会将其相加。
假定字符串在该范围内至少为7个连续字符。{7,}
。
对于外壳可读的输出,uchardet $file
返回对文件编码的猜测,该猜测将传递给iconv以进行自动插值。
uchardet
命令,这非常有用。感谢您的提示!