Как я могу определить странного персонажа?

10

Я пытаюсь определить странный символ, который я нашел в файле, с которым я работаю:

$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353  \n
0000002
$ od -x file
0000000 0aeb
0000002

Файл использует кодировку ISO-8859 и не может быть преобразован в UTF-8:

$ iconv -f ISO-8859 -t UTF-8 file
iconv: conversion from `ISO-8859' is not supported
Try `iconv --help' or `iconv --usage' for more information.
$ iconv  -t UTF-8 file
iconv: illegal input sequence at position 0
$ file file
file: ISO-8859 text

Мой главный вопрос: как я могу интерпретировать результаты odздесь? Я пытаюсь использовать эту страницу, которая позволяет мне переводить между различными символьными представлениями, но она говорит мне, что 005353«шестнадцатеричная кодовая точка» - это то, что не кажется правильным, 0aebа «шестнадцатеричная кодовая точка» - это то, что, опять же, кажется неправильным ,

Итак, как я могу использовать любого из трех вариантов ( 355, 005353или 0aeb) , чтобы выяснить , какой характер они должны представлять?

И да, я пробовал использовать инструменты Unicode, но он также не является допустимым символом UTF:

$ uniprops $(cat file)
U+FFFD ‹�› \N{REPLACEMENT CHARACTER}
    \pS \p{So}
    All Any Assigned Common Zyyy So S Gr_Base Grapheme_Base Graph X_POSIX_Graph
       GrBase Other_Symbol Print X_POSIX_Print Symbol Specials Unicode

если я понимаю описание символа Unicode U + FFFD, это вообще не настоящий символ, а заполнитель поврежденного символа. Что имеет смысл, поскольку файл на самом деле не в кодировке UTF-8.

Тердон
источник
5
EB может быть δ в кодовой странице 437 , или Ù в кодовой странице 850 , или ë в 8859-1 ; что-нибудь из этого имеет смысл? ( iconvжалуется, потому что вы не указали исходный набор символов, поэтому он использует ваше значение по умолчанию, которое, вероятно, UTF-8.)
Стивен Китт
@StephenKitt да, ëэто то , что я вижу, когда данные используются в другой программе! Но как я могу это знать? Разве это не где-то в данных, которые я предоставляю? Как ты это нашел? О, я пытался iconvс, -f ISO-8859но он жаловался на conversion from ISO-8859 «не поддерживается».
Terdon
1
Argh! Я вижу, мне нужно было просто использовать ebи игнорировать 0xшестнадцатеричный индикатор или что-то еще. Мое незнание такого рода вещей глубоко. Не могли бы вы опубликовать ответ, объясняющий, что @StephenKitt?
Тердон
5
Ваша критическая ошибка в том, что ISO-8859 не является названием кодировки. Это семья кодировок; очевидно, что вы ищете ISO-8859-1.
tripleee
1
Тогда iconvбы ты преуспел; и / или вы могли бы посмотреть это, например, в Википедии. Для этой очень специфической кодировки также работает fileformat.info/info/unicode/char/00eb/index.htm (Unicode эквивалентен ISO-8859-1 в диапазоне 128-255, хотя, конечно, ни одна UTF-кодировка не совместима с ним ).
tripleee

Ответы:

22

Ваш файл содержит два байта, EB и 0A в шестнадцатеричном виде. Вполне вероятно, что файл использует набор символов с одним байтом на символ, такой как ISO-8859-1 ; в этом наборе символов EB - это:

$ printf "\353\n" | iconv -f ISO-8859-1
ë

Другими кандидатами будут δ в кодовой странице 437 , Ù в кодовой странице 850 ...

od -xвывод в этом случае сбивает с толку из-за порядка байтов; лучший вариант, -t x1который использует одиночные байты:

$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002

od -xкарты, на od -t x2которые считываются два байта за раз, а в системах с прямым порядком байтов выводятся байты в обратном порядке.

Когда вы сталкиваетесь с файлом, подобным этому, который не является допустимым UTF-8 (или не имеет смысла, когда интерпретируется как файл UTF-8), не существует надежного способа автоматического определения его кодировки (и набора символов). Контекст может помочь: если это файл, созданный на западном ПК в последние пару десятилетий, вполне вероятно, что он закодирован в ISO-8859-1, -15 (вариант Euro) или Windows-1252; если он старше, CP-437 и CP-850 являются вероятными кандидатами. Файлы из восточноевропейских систем, российских систем или азиатских систем будут использовать разные наборы символов, о которых я мало что знаю. Тогда есть EBCDIC ... iconv -lперечислит все наборы символов, iconvо которых знает, и вы можете продолжить методом проб и ошибок оттуда.

(В какой-то момент я знал наизусть большинство CP-437 и ATASCII, это были дни.)

Стивен Китт
источник
1
Хорошо, на странице википедии, на которую вы ссылаетесь, я вижу, что ëописывается как 00EBи 234. Что это за лишнее 00? И почему это не так, 355как я ожидал от odвыхода? Я пытаюсь получить более общий ответ о том, как я могу использовать odвыходные данные для идентификации персонажа. Не могли бы вы объяснить что-то о интерпретации шестнадцатеричных кодов и / или какая информация необходима для идентификации неизвестного символа (кодирование и все остальное)?
Тердон
EB - 353 в восьмеричном (не 355). Я постараюсь обобщить ...
Стивен Китт
Ой, простите, я имел ввиду 353. Таким образом, 353 является восьмеричным представлением, а не десятичным. Argh.
Тердон
1
Да, «о» в odвосьмеричном означает ;-).
Стивен Китт
1
В любом случае (U + FFFD) будет отображаться эмулятором терминала в качестве замены этого байта 0xeb, который не образует допустимый символ в UTF-8. Непонятно, почему uniprops $(cat file)(пропущенные кавычки) сообщит об этом (я не знаю об этой unipropsкоманде). unicode "$(cat file)"на Debian выводит так, Sequence '\xeb' is not valid in charset 'UTF-8'как я ожидал.
Стефан
5

Обратите внимание, что odэто сокращение от восьмеричного дампа , поэтому 005353два байта в виде восьмеричного слова od -xпредставлены 0aebв шестнадцатеричном формате как слово, а фактическим содержимым вашего файла являются два байта ebи 0aв шестнадцатеричном формате, в этом порядке.

Так что и то, 005353и другое 0aebне может быть интерпретировано как «шестнадцатеричный код».

0aявляется переводом строки (LF) и ebзависит от вашей кодировки. fileпросто угадывает кодировку, это может быть что угодно. Без какой-либо дополнительной информации, откуда поступил файл и т. Д., Это будет трудно выяснить.

dirkt
источник
Я понимаю, что это потому, что я не понимаю, как работают кодовые точки (или шестнадцатеричные, действительно), но как я могу это знать? Я обычно использую, od -cтак как это производит вывод, который я могу понять. Как я мог использовать то, 355что производит, чтобы идентифицировать персонажа? И почему он печатает, 0aebа eb0aесли 0aперевод строки?
Тердон
@terdon endianness ... Смотрите мой обновленный ответ.
Стивен Китт
2

Невозможно со 100% точностью угадать кодировку текстовых файлов.

Такие инструменты, как chardet , firefox , file -i, когда явно не определена информация о наборе символов (например, если HTML содержит метасимвол = ... в голове, все проще), будут пытаться использовать эвристику, которая не так уж плоха, если текст достаточно большой.

Далее я продемонстрирую обнаружение кодировки с помощью chardet( pip install chardet/ apt-get install python-chardetпри необходимости).

$ echo "in Noël" | iconv -f utf8 -t latin1  | chardet
<stdin>: windows-1252 with confidence 0.73

После того , как кандидат хорошо кодировок, мы можем использовать iconv, recodeили аналогичные изменения файл кодового к вашей «активной» кодировке (в моем случае UTF-8) и посмотреть , если он угадал правильно ...

iconv -f windows-1252  -t utf-8 file

Некоторые наборы символов (например, iso-8859-3, iso-8859-1) имеют много общих символов - иногда непросто увидеть, нашли ли мы идеальный набор символов ...

Поэтому очень важно иметь метаданные, связанные с соответствующим текстом (например, XML).

JJoao
источник
Хм. Я не могу воспроизвести это здесь, это просто вылетает. Но в любом случае, разве это не говорит мне о кодировке файла? Моя проблема заключается в идентификации символа, а не кодировки файла. Это я уже знал.
Terdon
1
Извините, я не понял вопроса (моя обычная проблема - определение кодировки). если ты сейчас кодируешь, iconv -f ... -t utf-8 покажет тебе символы?
JJoao
Я показываю кодировку прямо там. Был один конкретный символ, не поддерживаемый этой кодировкой, и именно этот символ я пытался идентифицировать.
Terdon
1
Iso-8859 не кодировка! кодировка есть iso-8850-1. iso-8859 является стандартом iso и включает несколько определений chaset. Попробуйтеfile -i ...
JJoao
1
@terdon, извините, что настаиваю, но все уловки, которые вы пробовали, работают с правильной кодировкой. Пример: iconv -f ISO-8859-1 -t UTF-8 file
JJoao
0
#!/bin/bash
#
# Search in a file, a known (part of a ) String (i.E.: Begrüßung),
# by testing all encodings
#
[[ $# -ne 2 ]] && echo "Usage: encoding-finder.sh FILE fUnKy_CHAR_FOR_SURE_IN_FILE" && exit
FILE=$1
PATTERN=$2
for enc in $( iconv -l | sed 's/..$//') 
do 
    iconv -f $enc -t UTF-8 $FILE  2>/dev/null | grep -m 1 $PATTERN && echo $enc 
done 

Если я получу файл, который содержит, например, Слово Бегрунг, я могу сделать вывод, что Бегруссунг может иметь в виду. Поэтому я конвертирую его по всем известным кодировкам и смотрю, найден ли он, и который правильно конвертирует.

Обычно существует несколько кодировок, которые подходят.

Для более длинных файлов вы можете вырезать фрагмент вместо преобразования сотен страниц.

Я бы назвал это

encodingfinder.sh FILE Begrüßung

и сценарий проверяет, преобразует ли его с известными кодировками, какой из них производит «Begrüßung».

Чтобы найти таких персонажей, обычно помогает меньше, потому что часто выделяются забавные персонажи. Из контекста обычно можно вывести правильное слово для поиска. Но мы не хотим проверять с помощью hexeditor, что это за байт, а затем посещать бесконечные таблицы кодировок, чтобы найти нашего обидчика. :)

неизвестный пользователь
источник