web-dev-qa-db-ja.com

すべての非ASCII文字をgrepするにはどうすればいいですか?

私はいくつかの非常に大きなXMLファイルがあり、私は非ASCII文字を含む行を見つけようとしています。私は以下を試しました:

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

しかし、これは、指定された範囲の文字がその行に含まれているかどうかにかかわらず、ファイル内のすべての行を返します。

構文が間違っていますか、それとも別の問題をしていますか?私も試してみました:

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

(パターンを囲む一重引用符と二重引用符の両方)。

329
pconrey

あなたがコマンドを使用することができます:

grep --color='auto' -P -n "[\x80-\xFF]" file.xml

これはあなたに行番号を与えるでしょう、そして赤で非ASCII文字をハイライトするでしょう。

いくつかのシステムでは、あなたの設定によっては、上記はうまくいかないでしょう。

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

また、重要なのは-Pに相当する--Perl-regexpフラグです:それはあなたのパターンをPerlの正規表現として解釈するでしょう。それはまた言う

これは非常に実験的であり、grep -Pは未実装の機能について警告するかもしれません。

439
jerrymouse

上記の解決策のほとんどがそうであるように、非ASCII文字のバイト範囲について仮定するのではなく、代わりにASCII文字の実際のバイト範囲について明示的になる方がわずかに良いIMOです。

したがって、たとえば最初の解決策は次のようになります。

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

(基本的に、16進数のASCIIの範囲外のすべての文字に対応します:\ x00から\ x7Fまで)

Mountain Lionではうまくいきません(BSD grepではPCREがサポートされていないため)、しかしHomebrew経由でインストールされたpcreでは以下がうまくいきます同様に:

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

だれでも考えることができる賛否両論?

109
pvandenberk

以下は私のために働きます:

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

非ASCII文字は0x80から始まり、バイトを見ると0xFFになります。 Grep(およびそのファミリー)は、正規表現のマッチングのためにマルチバイト文字を単一のエンティティーにマージするUnicode処理を行いません。私のgrepの-Pオプションは文字クラスの中で\xddエスケープを使用してあなたが望むことを達成することを可能にします。

66
Thelema

Perlでは

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

簡単な方法は、非ASCII文字をASCII文字ではない文字として定義することです。

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

必要に応じて^の後にタブを追加してください。

LC_COLLATE=Cを設定することは、多くのロケールで文字範囲の意味についての厄介な驚きを避けます。シングルバイト文字と一致させるにはLC_CTYPE=Cを設定する必要があります。そうしないと、現在のエンコーディングで無効なバイトシーケンスが失われる可能性があります。 LC_ALL=Cを設定すると、ロケールに依存する影響を完全に回避できます。

38
Gilles

これが私が見つけたもう一つの変種で、受け入れられた答えの中で[\x80-\xFF]のgrep検索から完全に異なる結果を生み出しました。おそらく、他の非ASCII文字を見つけることが誰かに役立つでしょう:

grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt

注:私のコンピューターのgrep(Mac)は-Pオプションを持っていなかったので、私はbrew install grepをし、ggrepの代わりにgrepを使って上記の呼び出しを始めました。

21
ryanm

次のコードは機能します。

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

/tmpを検索したいディレクトリの名前に置き換えます。

8
user7417071

印刷できない文字を検索しています。

私は上記の Harvey に賛成しますが、印刷不可能な文字を検索するほうがより便利ですOR簡単ですあなたが本当に印刷不可能であると考えるべきであるときに非ASCIIであると考えるため。 Harvey は「これを使用してください:」[^\n - 〜]を使用します。DOSテキストファイルには\ rを追加してください。これは「[^\x0A」に変換されます。\x020-\x07E] "そしてCRに\ x0Dを追加"

また、grepに-c(一致したパターンの数を表示)を追加すると、一致した文字列が端末をめちゃくちゃにする可能性があるので、印刷不能文字を検索するときに便利です。

範囲0-8と0x0e-0x1f(0x80-0xffの範囲)を追加すると便利なパターンです。これは、TAB、CR、LF、および1つまたは2つ以上の一般的でない印刷可能文字を除外します。だから私見非常に便利な(粗いにもかかわらず)grepパターンはこれです:

grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *

壊す:

\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

例えば。現在のディレクトリの下にあるすべてのファイルをgrepするためのfindの使用例

find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} + 

あなたは時々grepを調整したいかもしれません。例えばBS(0x08 - backspace)charいくつかの印刷可能なファイルで使われるか、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
4
gaoithe

奇妙なことに、私は今日これをしなければなりませんでした! grep/egrepを動作させることができなかったので(-Pモードでも)Perlを使用することになりました。何かのようなもの:

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 }' '{}' \;
1
dty

すべての非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

前の回答で述べたように、Vanilla grepはLC_ALL = Cがないと正しく動作しません。

ASCIIの範囲はx00-x7F、スペースはx20です。文字列にはスペースが含まれるため、負の範囲では省略されます。

文字列にはスペースが含まれるため、ASCII以外の範囲はx80-xFFで、正の範囲に追加されます。

文字列は範囲内で少なくとも7文字連続していると推定されます。 {7,}

シェルが読み取り可能な出力の場合、uchardet $fileは自動補間のためにiconvに渡されるファイルエンコーディングの推測を返します。

0
noabody

1つのUnicode文字を検索する方法を知っているのは面白いかもしれません。このコマンドは役に立ちます。あなただけのUTF8のコードを知る必要があります

grep -v $'\u200d'
0
arezae