Как я grep для всех не-ASCII символов?

292

У меня есть несколько очень больших XML файлов, и я пытаюсь найти строки, содержащие не-ASCII-символы. Я пробовал следующее:

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

Но это возвращает каждую строку в файле, независимо от того, содержит ли строка символ в указанном диапазоне.

У меня синтаксис неправильный или я делаю что-то еще неправильно? Я также пробовал:

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

(с одиночными и двойными кавычками, окружающими шаблон).

  • 0
    Символы ASCII имеют длину только один байт, поэтому, если файл не является юникодом, не должно быть символов выше 0xFF.
  • 0
    Как мы пойдем выше \ xFF? Grep выдает ошибку «grep: диапазон не по порядку в классе символов».
Теги:
grep
unicode

10 ответов

387
Лучший ответ

Вы можете использовать команду:

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 может предупредить о невыполнении особенности.

  • 36
    Это не будет работать в grep BSD (на OS X 10.8 Mountain Lion), так как он не поддерживает опцию P
  • 20
    Чтобы обновить мой последний комментарий, GNU-версия grep доступна в библиотеке dupes Homebrew (включите с помощью brew tap homebrew/dupes ): brew install grep
Показать ещё 21 комментарий
88

Вместо того, чтобы делать предположения о байтовом диапазоне символов, отличных от ASCII, как это делает большинство из вышеперечисленных решений, это немного лучше, чем IMO, чтобы явно указывать фактический диапазон байтов символов ASCII.

Итак, первое решение, например, станет:

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

(который в основном greps для любого символа вне шестнадцатеричного диапазона ASCII: от \x00 до\x7F)

На Mountain Lion, который не будет работать (из-за отсутствия поддержки PCRE в BSD grep), но с pcre, установленным через Homebrew, следующее будет работать так же хорошо:

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

Любые плюсы или минусы, которые любой может придумать?

  • 9
    Это на самом деле сработало для меня, где вышеперечисленные решения не удалось. Найти апострофы M $ Word еще проще!
  • 1
    Если у вас есть bash-совместимая оболочка, но не работает pcre-grep, LC_COLLATE=C grep $'[^\1-\177]' работает (для файлов без нулевых байтов)
Показать ещё 4 комментария
68

Для меня работает следующее:

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

Символы, отличные от ASCII, начинаются с 0x80 и переходят к 0xFF при просмотре байтов. Grep (и семья) не обрабатывают Юникод, чтобы объединить многобайтовые символы в единый объект для соответствия регулярных выражений, как вам кажется. Опция -P в моем grep позволяет использовать \xdd escape-последовательности в классах символов для выполнения того, что вы хотите.

  • 1
    Для представления, которое может не сразу знать, как вызвать это для нескольких файлов, просто запустите: find. имя * .xml | xargs grep -P "[\ x80- \ xFF]"
  • 1
    Это возвращает совпадение, но нет никаких указаний на то, что это за персонаж и где он находится. Как увидеть, что это за персонаж и где он?
Показать ещё 3 комментария
43

В perl

perl -ane '{ if(m/[[:^ascii:]]/) { print  } }' fileName > newFile
  • 0
    Около -1 для бесполезного использования кота. См. Patrmaps.org/era/unix/award.html.
  • 0
    Я согласен с @tripleee. Вы можете редактировать свой ответ
Показать ещё 6 комментариев
31

Простым способом является определение символа не ASCII... как символ, который не является символом ASCII.

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

При необходимости добавьте вкладку после ^.

Настройка LC_COLLATE=C позволяет избежать неприятных сюрпризов о значении диапазонов символов во многих локалях. Настройка LC_CTYPE=C необходима для соответствия однобайтовых символов, иначе команда будет пропускать недопустимые последовательности байтов в текущей кодировке. Установка LC_ALL=C полностью исключает зависящие от локали эффекты.

  • 0
    На RedHat 6.4 с tcsh мне пришлось использовать <<< env LC_COLLATE = C grep -n '[^ - ~]' file.xml >>>. Я добавил -n, чтобы получить номер строки.
  • 0
    Для меня echo "A" | LC_COLLATE=C grep '[^ -~]' возвращает совпадение
Показать ещё 10 комментариев
16

Вот еще один вариант, который я нашел, который дал совершенно разные результаты поиска grep для [\x80-\xFF] в принятом ответе. Возможно, кому-то будет полезно найти дополнительные символы не-ascii:

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

Примечание. У моего компьютера grep (a Mac) не было опции -P, поэтому я сделал brew install grep и начал вызов выше с помощью ggrep вместо grep.

  • 1
    Это, безусловно, лучший ответ, поскольку он работает как для Mac, так и для Linux.
5

Работает следующий код:

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

Замените /tmp именем каталога, который вы хотите выполнить.

  • 1
    На Mac это работает, а большинство основанных на grep - нет.
1

Странно, я должен был сделать это сегодня! Я закончил использование 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 }' '{}' \;
0

Поиск непечатаемых символов.

Я согласен с Harvey выше, похороненным в комментариях, часто более полезно искать непечатаемые символы или легко думать, что не-ASCII когда вы действительно должны думать о непечатаемой. Harvey предлагает "использовать это:" [^\n - ~] ". Добавить \r для текстовых файлов DOS. Это переводится как" [^\x0A\x020 -\x07E] "и добавьте \x0D для CR"

Кроме того, добавление -c (показать количество сопоставленных шаблонов) в grep полезно при поиске непечатаемых символов, поскольку строки, сопоставленные, могут испортить терминал.

Я обнаружил, что добавление диапазона 0-8 и 0x0e-0x1f (к диапазону 0x80-0xff) является полезным шаблоном. Это исключает TAB, CR и LF и один или два необычных печатаемых символа. Таким образом, IMHO a довольно полезный (хотя и грубый) шаблон 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

например. практический пример использования find для grep всех файлов в текущем каталоге:

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
0

Интересно было бы узнать, как искать один символ Юникода. Эта команда может помочь. Вам нужно только знать код в UTF8

grep -v $'\u200d'
  • 0
    Я не совсем эксперт, но знаю достаточно, чтобы понять, что это не представление UTF8, это UTF16, или, может быть, UTF32 или UCS16. Для двухбайтовой кодовой точки эти три могут быть одинаковыми.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню