У меня есть несколько очень больших 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
Это даст вам номер строки и выделит красные символы не-ascii.
В некоторых системах, в зависимости от ваших настроек, вышеуказанное не будет работать, поэтому вы можете grep с помощью обратного
grep --color='auto' -P -n "[^\x00-\x7F]" file.xml
Обратите внимание, что важным битом является флаг -P
, который равен --perl-regexp
: поэтому он будет интерпретировать ваш шаблон как регулярное выражение Perl. В нем также говорится, что
это очень экспериментально, и grep -P может предупредить о невыполнении особенности.
grep
BSD (на OS X 10.8 Mountain Lion), так как он не поддерживает опцию P
grep
доступна в библиотеке dupes
Homebrew (включите с помощью brew tap homebrew/dupes
): brew install grep
Вместо того, чтобы делать предположения о байтовом диапазоне символов, отличных от 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
Любые плюсы или минусы, которые любой может придумать?
LC_COLLATE=C grep $'[^\1-\177]'
работает (для файлов без нулевых байтов)
Для меня работает следующее:
grep -P "[\x80-\xFF]" file.xml
Символы, отличные от ASCII, начинаются с 0x80 и переходят к 0xFF при просмотре байтов. Grep (и семья) не обрабатывают Юникод, чтобы объединить многобайтовые символы в единый объект для соответствия регулярных выражений, как вам кажется. Опция -P
в моем grep позволяет использовать \xdd
escape-последовательности в классах символов для выполнения того, что вы хотите.
В perl
perl -ane '{ if(m/[[:^ascii:]]/) { print } }' fileName > newFile
Простым способом является определение символа не ASCII... как символ, который не является символом ASCII.
LC_ALL=C grep '[^ -~]' file.xml
При необходимости добавьте вкладку после ^
.
Настройка LC_COLLATE=C
позволяет избежать неприятных сюрпризов о значении диапазонов символов во многих локалях. Настройка LC_CTYPE=C
необходима для соответствия однобайтовых символов, иначе команда будет пропускать недопустимые последовательности байтов в текущей кодировке. Установка LC_ALL=C
полностью исключает зависящие от локали эффекты.
echo "A" | LC_COLLATE=C grep '[^ -~]'
возвращает совпадение
Вот еще один вариант, который я нашел, который дал совершенно разные результаты поиска grep для [\x80-\xFF]
в принятом ответе. Возможно, кому-то будет полезно найти дополнительные символы не-ascii:
grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Примечание. У моего компьютера grep (a Mac) не было опции -P
, поэтому я сделал brew install grep
и начал вызов выше с помощью ggrep
вместо grep
.
Работает следующий код:
find /tmp | perl -ne 'print if /[^[:ascii:]]/'
Замените /tmp
именем каталога, который вы хотите выполнить.
Странно, я должен был сделать это сегодня! Я закончил использование 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 }' '{}' \;
Поиск непечатаемых символов.
Я согласен с 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
Интересно было бы узнать, как искать один символ Юникода. Эта команда может помочь. Вам нужно только знать код в UTF8
grep -v $'\u200d'