我有几个非常大的XML文件,我正在尝试找到包含非ASCII字符的行。我尝试了以下方法:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
但是这会返回文件中的每一行,不管该行是否包含指定范围内的字符。
我是语法出错了还是做错了其他什么事情?我还尝试过:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(模式周围同时使用单引号和双引号)。
grep --color='auto' -P -n "[\x80-\xFF]" file.xml
grep --color='auto' -P -n "[^\x00-\x7F]" file.xml
-P
标志,它等同于--perl-regexp
:因此它会将您的模式解释为Perl正则表达式。它还指出:
这是非常实验性的,grep -P可能会警告未实现的功能。
grep
(在 OS X 10.8 Mountain Lion 上)中,这不起作用,因为它不支持 P
选项。 - Bastiaan M. van de Weerdgrep
可以在 Homebrew 的 dupes
库中使用(启用方式为 brew tap homebrew/dupes
):brew install grep
。 - Bastiaan M. van de Weerdbrew install pcre
...作为安装的一部分,您将获得pcregrep
实用程序,您可以按以下方式使用它:pcregrep --color='auto' -n "[\x80-\xFF]" file.xml
。 - pvandenberkbrew
用户,可以使用brew install coreutils
安装GNU的核心工具集。这将为您提供以“g”为前缀的许多GNU工具-在这种情况下使用ggrep
。这样可以避免由于替换系统实用程序而引起的问题,因为特定于系统的Mac脚本现在依赖于BSD grep。 - Joel Purraag "[\x80-\xFF]" file
,你只需要安装 the_silver_searcher
即可。 - slf与上述大部分解决方案一样,不要对非ASCII字符的字节范围进行假设,我认为更好的做法是明确ASCII字符实际的字节范围。
因此,例如第一个解决方案将变为:
Instead of making assumptions about the byte range of non-ASCII characters, as most of the above solutions do, it's slightly better IMO to be explicit about the actual byte range of ASCII characters instead.
So the first solution for instance would become:
grep --color='auto' -P -n '[^\x00-\x7F]' file.xml
(这基本上是在十六进制ASCII范围之外查找任何字符的grep:从\x00到\x7F)
在Mountain Lion中,由于BSD grep缺乏PCRE支持,这不起作用,但是通过Homebrew安装pcre
后,以下内容也能正常工作:
pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml
有人能想到的任何优点或缺点吗?
LC_COLLATE=C grep $'[^\1-\177]'
可以工作(对于没有空字节的文件)。 - idupree简单的方法是将非ASCII字符定义为不是ASCII字符的字符。
LC_ALL=C grep '[^ -~]' file.xml
如果必要的话,在^
后添加一个制表符。
设置LC_COLLATE=C
可以避免在许多语言环境中出现有关字符范围含义的令人讨厌的意外情况。设置LC_CTYPE=C
是匹配单字节字符所必需的 - 否则,该命令将错过当前编码中的无效字节序列。设置LC_ALL=C
可以完全避免依赖于语言环境的效果。
LC_ALL=en_US.UTF-8
,那么它会覆盖 LC_COLLATE
的设置。你的环境中不应该有这个设置!LC_ALL
只应用于强制指定某个任务使用特定的地区设置,通常是 C
。如果要设置所有类别的默认地区设置,请设置 LANG
。 - Gilles 'SO- stop being evil'LC_ALL=C
再次运行。 - Gilles 'SO- stop being evil'LC_ALL=C
,在 Mac OS X 和 Ubuntu 上的行为不同。在我添加了这个设置之后,它们给出了相同的结果。 - Max Penggrep -P "[\x80-\xFF]" file.xml
echo '소녀시대' | grep -P "[\x80-\xFF]"
对我来说没有返回结果——有人能否确认一下?(使用GNU grep 2.21) - frabjousecho '소녀시대' | grep -P "[^\x00-\x7F]"
。或者像@slf指出的那样直接使用the_silver_searcher
:echo '소녀시대' | ag "[\x80-\xFF]"
。 - psmithperl -ane '{ if(m/[[:^ascii:]]/) { print } }' fileName > newFile
perl -lne 'print if /[^[:ascii:]]/' file.xml
翻译为中文是:在文件 file.xml
中,使用 Perl 编程语言读取每一行,并打印出包含非 ASCII 字符的行。 - Naveed这是我找到的另一种变体,它产生了与接受答案中的 [\x80-\xFF]
grep 搜索完全不同的结果。或许对于某些人来说,找到额外的非 ASCII 字符会有用:
grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
注意:我的电脑上的 grep(一台 Mac)没有 -P
选项,所以我执行了 brew install grep
并使用 ggrep
而不是 grep
开始了上述调用。
LC_ALL=C
像这样 LC_ALL=C grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
之前,它对我不起作用。 - Praveen Lobo查找不可打印字符。简介
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
与顶部答案相同,但使用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]
”,并加上\x0D表示CR。
另外,在grep命令中加入-c(显示匹配模式数)在搜索非可打印字符时非常有用,因为匹配的字符串可能会搞乱终端。
我发现将范围0-8和0x0e-0x1f(添加到0x80-0xff范围内)排除是一个有用的模式。这将排除制表符、回车和换行符以及其他一两个不常见的可打印字符。所以,在我看来,一个相当有用(尽管粗略)的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查找所有文件的实际示例:
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
更新:最近我不得不重新访问这个问题。取决于终端设置/太阳天气预报,但是我注意到grep无法找到许多unicode或扩展字符。尽管在直觉上它们应该匹配范围0x80到0xff,但是3字节和4字节的unicode字符没有被匹配。??? 有人能解释一下吗?是的。@frabjous问了,@calandoa解释说应该使用 LC_ALL=C
来设置命令的区域设置以使grep匹配。
例如,我的区域设置为 LC_ALL=
empty
$ locale
LANG=en_IE.UTF-8
LC_CTYPE="en_IE.UTF-8"
.
.
LC_ALL=
使用LC_ALL=
的grep可以匹配2字节编码字符但不能匹配3或4字节编码字符:
$ 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
使用LC_ALL=C
的grep似乎可以匹配所有你想要的扩展字符:
$ 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,似乎都能找到所有“奇怪”的和“美妙的”“非 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
就像最佳答案一样,但加上LC_ALL=C
:
$ LC_ALL=C grep --color='auto' -P -n "[\x80-\xFF]" notes_unicode_emoji_test
find /tmp | perl -ne 'print if /[^[:ascii:]]/'
/tmp
替换为您想要搜索的目录名称。find ./folder -print -exec perl -ne 'print if /[^[:ascii:]]/' {} \;
- undefinedawk
和iconv
版本。
我们还可以利用file
和tr
。curl
不是POSIX的。$ curl -LOs http://gutenberg.org/files/84/84-0.txt
$ file 84-0.txt
84-0.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
搜索UTF-8字符:
$ awk '/[\x80-\xFF]/ { print }' 84-0.txt
或非ASCII字符(实际上不是POSIX,参见下面的可能解决方案)
$ awk '/[^[:ascii:]]/ { print }' 84-0.txt
将UTF-8转换为ASCII,删除有问题的字符(包括BOM,它本来就不应该出现在UTF-8中):
$ iconv -c -t ASCII 84-0.txt > 84-ascii.txt
检查一下:
$ file 84-ascii.txt
84-ascii.txt: ASCII text, with CRLF line terminators
调整它以去除DOS行尾/ ^M
("CRLF行终止符"):
$ tr -d '\015' < 84-ascii.txt > 84-tweaked.txt && file 84-tweaked.txt
84-tweaked.txt:ASCII文本
这种方法会丢弃无法处理的任何“坏”字符,因此您可能需要对输出进行清理/验证。 YMMV
>> 更新 << 我最近使用了类似于这个的东西:
$ LC_ALL=C tr -d '[:print:]' < 84-0.txt | fold -w 1 | sort -u | sed -n l
但我不确定它有多可移植,但它给我提供了自动替换字符或字符串的选项。
我现在没有快速访问真正的UNIX,但我认为这些都是符合POSIX标准的选项和开关。我知道它运行得相当快。 YMMV。
/[^[:ascii:]]/
在任何符合 POSIX 标准的 awk 中都不应该是有效的。 - RARE Kpop Manifestocat 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 }' '{}' \;
tr <file.txt -d '\000-\177' >foo.out && ls -al foo.out
来获取计数。然后可以使用od -x foo.out
查看实际值。 - Ron Burk