Как grep для всех символов, отличных от ASCII?
У меня есть несколько очень больших XML файлов, и я пытаюсь найти строки, содержащие не-ASCII-символы. Я пробовал следующее:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
Но это возвращает каждую строку в файле, независимо от того, содержит ли строка символ в указанном диапазоне.
У меня синтаксис неправильный или я делаю что-то еще неправильно? Я также пробовал:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(с одиночными и двойными кавычками, окружающими шаблон).
Ответы
Ответ 1
Вы можете использовать команду:
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 может предупредить о невыполнении особенности.
Ответ 2
Вместо того, чтобы делать предположения о байтовом диапазоне символов, отличных от 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
Любые плюсы или минусы, которые любой может придумать?
Ответ 3
Для меня работает следующее:
grep -P "[\x80-\xFF]" file.xml
Символы, отличные от ASCII, начинаются с 0x80 и переходят к 0xFF при просмотре байтов. Grep (и семья) не обрабатывают Юникод, чтобы объединить многобайтовые символы в единый объект для соответствия регулярных выражений, как вам кажется. Опция -P
в моем grep позволяет использовать \xdd
escape-последовательности в классах символов для выполнения того, что вы хотите.
Ответ 4
В perl
perl -ane '{ if(m/[[:^ascii:]]/) { print } }' fileName > newFile
Ответ 5
Простым способом является определение символа не ASCII... как символ, который не является символом ASCII.
LC_ALL=C grep '[^ -~]' file.xml
При необходимости добавьте вкладку после ^
.
Настройка LC_COLLATE=C
позволяет избежать неприятных сюрпризов о значении диапазонов символов во многих локалях. Настройка LC_CTYPE=C
необходима для соответствия однобайтовых символов, иначе команда будет пропускать недопустимые последовательности байтов в текущей кодировке. Установка LC_ALL=C
полностью исключает зависящие от локали эффекты.
Ответ 6
Вот еще один вариант, который я нашел, который дал совершенно разные результаты поиска grep для [\x80-\xFF]
в принятом ответе. Возможно, кому-то будет полезно найти дополнительные символы не-ascii:
grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Примечание. У моего компьютера grep (a Mac) не было опции -P
, поэтому я сделал brew install grep
и начал вызов выше с помощью ggrep
вместо grep
.
Ответ 7
Работает следующий код:
find /tmp | perl -ne 'print if /[^[:ascii:]]/'
Замените /tmp
именем каталога, который вы хотите выполнить.
Ответ 8
Поиск не -P промываемых символов. TLDR; Резюме
поиск контрольных символов и расширенного юникода
настройка локали, например LC_ALL = C необходим, чтобы grep делал то, что вы могли ожидать с расширенным юникодом
Так что предпочтительные не-ASCII Char Finders:
$ perl -ne 'вывести "$. $ _", если 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
,, Больше., Мучительная деталь в этом:,.
Я согласен с Харви выше, похороненным в комментариях, часто более полезно искать не -P промываемые символы ИЛИ легко думать не ASCII, когда вы действительно должны думать не -P ополаскиваемый, Харви предлагает "использовать это:" [^\n - ~] ". Добавить \r для текстовых файлов DOS. Это означает" [^\x0A\x020-\x07E] "и добавить \x0D для ЧР "
Кроме того, добавление -c (показывать количество совпавших шаблонов) в grep полезно при поиске не опрашиваемых символов -P, так как совпавшие строки могут испортить терминал.
Я обнаружил, что добавление диапазона 0-8 и 0 x0E- 0x1f (к диапазону 0 x80- 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 для поиска всех файлов в текущем каталоге:
LC_ALL=C find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} +
Вы можете иногда настраивать grep. например Символ BS (0x08 - backspace), используемый в некоторых печатаемых файлах или для исключения 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 в зависимости от настроек терминала/прогноза солнечной погоды, НО., Я заметил, что grep не находил много юникодов или расширенных символов. Хотя интуитивно они должны соответствовать диапазону от 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=
grep с LC_ALL = пусто соответствует 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
grep с 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 в верхнем ответе, похоже, обнаруживает ВСЕ странные ~ и ~ чудесные ~ "не-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 'напечатать "$. $ _", если 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
Ответ 9
Странно, я должен был сделать это сегодня! Я закончил использование 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 }' '{}' \;
Ответ 10
Интересно было бы узнать, как искать один символ Юникода. Эта команда может помочь. Вам нужно только знать код в UTF8
grep -v $'\u200d'
Ответ 11
Поиск всех символов, не относящихся к ascii, создает впечатление, что кто-то ищет строки в юникоде или намеревается удалить эти символы по отдельности.
В первом случае попробуйте один из них (переменная 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
Ванильный grep не работает правильно без LC_ALL = C, как отмечалось в предыдущих ответах.
ASCII-диапазон - x00-x7F
, пробел - x20
, поскольку в строках есть пробелы, которые отрицательный диапазон пропускает.
Диапазон, отличный от ASCII, равен x80-xFF
, поскольку в строках есть пробелы, положительный диапазон добавляет его.
Предполагается, что строка должна содержать не менее 7 последовательных символов в диапазоне. {7,}
.
Для вывода, читаемого оболочкой, uchardet $file
возвращает предположение о кодировке файла, которая передается в iconv для автоматической интерполяции.