У меня есть текстовый файл в неизвестной или смешанной кодировке. Я хочу видеть строки, которые содержат последовательность байтов, которая не является допустимой UTF-8 (путем передачи текстового файла в какую-то программу). Эквивалентно, я хочу отфильтровать строки, которые являются действительными UTF-8. Другими словами, я ищу .grep [notutf8]
Идеальное решение было бы переносимым, коротким и обобщаемым для других кодировок, но если вы чувствуете, что лучше всего испечь определение UTF-8 , продолжайте.
command-line
text-processing
character-encoding
unicode
Жиль "ТАК - перестань быть злым"
источник
источник
Ответы:
Если вы хотите использовать
grep
, вы можете сделать:в локалях UTF-8, чтобы получить строки, которые имеют по крайней мере недопустимую последовательность UTF-8 (это работает по крайней мере с GNU Grep).
источник
-a
, что требуется для работы POSIX. Однако GNU,grep
по крайней мере, не может обнаружить суррогатные не-символы или кодовые точки UTF-8 в кодировке UTF-8 выше 0x10FFFF.-a
необходим GNUgrep
(который, я полагаю, не соответствует POSIX). Что касается суррогатной области и кодовых точек выше 0x10FFFF, то это ошибка (которая может объяснить это ). Для этого добавление-P
должно работать с GNUgrep
2.21 (но медленно); глючит по крайней мере в Debian grep / 2.20-4 .grep
как это текстовая утилита (ожидается, что она будет работать только при вводе текста), поэтому я предполагаю, что поведение GNU grep так же верно, как и любое другое здесь.grep
(цель которой состоит в том, чтобы рассматривать недопустимые последовательности как несоответствующие) и возможные ошибки.Я думаю, что вы, вероятно, хотите iconv . Это для преобразования между наборами кодов и поддерживает абсурдное количество форматов. Например, чтобы удалить что-то недопустимое в UTF-8, вы можете использовать:
iconv -c -t UTF-8 < input.txt > output.txt
Без опции -c он сообщит о проблемах при конвертации в stderr, поэтому с указанием направления процесса вы можете сохранить их список. Другим способом было бы раздеть материал не-UTF8, а затем
diff input.txt output.txt
для списка, где были внесены изменения.
источник
iconv -c -t UTF-8 <input.txt | diff input.txt - | sed -ne 's/^< //p'
. Тем не менее, он не будет работать как конвейер, так как вам нужно прочитать вход дважды (нет,tee
не будет, он может блокироваться в зависимости от того, сколько буферизацииiconv
и сколькоdiff
нужно).diff <(iconv -c -t UTF-8 <input.txt) input.txt
Редактировать: я исправил опечатку в регулярном выражении. Нужно было \ x80, а не \ 80 .
Регулярное выражение для фильтрации недействительных форм UTF-8 для строгого соблюдения UTF-8 выглядит следующим образом
Вывод (из ключевых строк. Из теста 1 ):
В. Как создать тестовые данные для проверки регулярного выражения, которое фильтрует недопустимый Unicode?
A. Создайте свой собственный алгоритм тестирования UTF-8 и нарушите его правила ...
Catch-22 .. Но как же тогда вы протестируете свой алгоритм тестирования?
Вышеуказанное регулярное выражение было протестировано (с использованием
iconv
в качестве ссылки) для каждого целочисленного значения от0x00000
до0x10FFFF
. Это верхнее значение является максимальным целочисленным значением кодовой точки UnicodeСогласно этой странице википедии UTF-8 .
Это Numeber (1112064) приравнивается к диапазону
0x000000
к0x10F7FF
, который является 0x0800 стесняется фактического максимального значения целочисленной для самого высокого Unicode элемент кода:0x10FFFF
Этот блок целых чисел отсутствует в спектре кодовых точек Unicode из-за необходимости того, чтобы кодирование UTF-16 выходило за рамки своего первоначального замысла через систему, называемую суррогатными парами . Блок
0x0800
целых чисел зарезервирован для использования UTF-16. Этот блок охватывает диапазон0x00D800
до0x00DFFF
. Ни одно из этих целых чисел не является допустимыми значениями Unicode и, следовательно, недопустимыми значениями UTF-8.В тесте 1 ,
regex
было проверено против каждого числа в диапазоне кодовых точек Unicode, и это точно совпадает с результатамиiconv
.. т.е. 0x010F7FF допустимые значения и 0x000800 недопустимые значения.Однако теперь возникает проблема: * Как регулярное выражение обрабатывает значение UTF-8 вне диапазона; выше
0x010FFFF
(UTF-8 может расширяться до 6 байтов с максимальным целочисленным значением 0x7FFFFFFF ?Чтобы сгенерировать необходимые * не-Unicode значения байтов UTF-8 , я использовал следующую команду:
Чтобы проверить их достоверность (некоторым образом), я использовал
Gilles'
регулярное выражение UTF-8 ...Вывод 'perl's print chr' совпадает с фильтрацией регулярного выражения Жиля. Один подтверждает правильность другого. Я не могу использовать,
iconv
потому что он обрабатывает только подмножество valid-Unicode Standard более широкого (оригинального) UTF-8. стандарт ...Вовлеченные nunbers довольно велики, поэтому я тестировал верхние, нижние и несколько сканирований с пошаговым шагом, например, 11111, 13579, 33333, 53441 ... Все результаты совпадают, так что теперь все, что остается, это проверить регулярное выражение на соответствие этим значениям вне UTF-8-стиля (недопустимо для Unicode, и, следовательно, также недопустимо для самого строгого UTF-8).
Вот тестовые модули:
источник
\300\200
(очень плохо: это кодовая точка 0, не выраженная нулевым байтом!). Я думаю, что ваше регулярное выражение отклоняет их правильно.Я нахожу
uconv
(вicu-devtools
пакете в Debian) полезным для проверки данных UTF-8:(
\x
Помогает определить недопустимые символы (за исключением ложного срабатывания, добровольно введенного с литералом\xE9
выше)).(множество других приятных приемов).
источник
recode
можно использовать аналогично - за исключением того, что я думаю, что он потерпит неудачу, если его попросят перевести неверную многобайтовую последовательность. Я не уверен, хотя; она не подведет наprint...|recode u8..u8/x4
, например (который просто делает шестнадцатеричную как вы делаете выше) , потому что он ничего не делает , ноiconv data data
, но он терпит неудачу , какrecode u8..u2..u8/x4
потому , что он переводит затем печатает. Но я не знаю достаточно об этом, чтобы быть уверенным - и есть много возможностей.test.txt
. Как я должен предполагать, чтобы найти недопустимый символ, используя ваше решение? Что означаетus
в вашем коде?us
значит США, это сокращение от ASCII. Он преобразует входные данные в ASCII, где не-ASCII-символы преобразуются в\uXXXX
нотацию, а не-символы - в\xXX
.Python имеет встроенную
unicode
функцию начиная с версии 2.0.В Python 3
unicode
был свернут вstr
. Ему нужно передать байтовоподобный объект , здесь базовыеbuffer
объекты для стандартных дескрипторов .источник
python 2
Один флаг не в UTF-8 закодированные в UTF-16 суррогатных не-символов (по крайней мере с 2.7.6).Я столкнулся с подобной проблемой (подробно в разделе «Контекст») и пришел со следующим решением ftfy_line_by_line.py :
Использование encode + replace + ftfy для автоматического исправления Моджибаке и других исправлений.
контекст
Я собрал> 10GiB CSV основных метаданных файловой системы, используя следующий сценарий gen_basic_files_metadata.csv.sh , выполняющийся по существу:
Беда у меня было с несовместимым кодирования имен файлов через файловые системы, в результате чего
UnicodeDecodeError
при обработке далее с питона приложений ( csvsql быть более точным).Поэтому я применил выше сценарий ftfy, и это заняло
Пожалуйста, обратите внимание, что ftfy работает довольно медленно, обработка этих> 10 ГБ заняла:
пока sha256sum для сравнения:
на процессоре Intel® Core ™ TM i7-3520M @ 2,90 ГГц + 16 ГБ ОЗУ (и данные на внешнем диске)
источник