Я пытаюсь преобразовать файл из utf-8 в ms-ansi.
я использую
iconv -f UTF8 -t MS-ANSI// < data.txt
но получить
iconv: illegal input sequence at position 171359
при рассмотрении этого вопроса
dd if=data.txt of=error.txt bs=1 count=10 skip=171359
Я понимаю это:
hexdump -C error.txt
00000000 ef bb bf 38 3a 6e 61 09 38 3a |...8:na.8:|
0000000a
файл не utf-8, и если нет, что мне следует использовать вместо iconv?
решение1
$ printf '\xef\xbb\xbf' | uconv -x any-name
\N{ZERO WIDTH NO-BREAK SPACE}
Это символ (U+FEFF, закодированный в 3 байтах в UTF-8), который также используется как byte-order-mark. В любом случае, этот символ не найден в MS-ANSI (неправильное название, иногда даваемое windows-1252, надмножеству iso8859-1), поэтому не может быть преобразован в него.
BOM используются (в начале некоторого текста) для различения UTF16-LE от UTF16-BE (или других небайтовых кодировок, на которые влияет порядок байтов ЦП). Это не имеет смысла в UTF-8, где нет неоднозначности порядка байтов, это будет иметь еще меньше смысла в windows-1252, которая является однобайтовой кодировкой символов. Как "пробел нулевой ширины без разрыва", он также невидим и не имеет свойства разделения слов, как символ "пробел нулевой ширины", поэтому, вероятно, его можно безопасно удалить вообще.
С zsh
, bash
или ksh93
:
sed $'s/\ufeff//g' < input | iconv -t windows-1252
В некоторых iconv
реализациях вы также можете использовать:
iconv -t windows-1252//translit < input
//translit
прибегает к приближениям, когда текст не может быть точно переведен. В этом случае он просто удаляет символ U+FEFF.
$ printf '\xef\xbb\xbf\x38\x3a\x6e\x61\x09\x38\x3a' |
iconv -t windows-1252//translit | hd
00000000 38 3a 6e 61 09 38 3a |8:na.8:|
00000007
Другим вариантом может быть использование:
iconv -t utf-16le | iconv -f utf-16 -t windows-1252
Первый iconv
преобразует в UTF-16 little-endian без BOM, но начальный U+FEFF фактически делает его UTF-16 с BOM, поэтому второй iconv
удаляет BOM, поскольку он используется для определения порядка байтов этой utf-16
кодировки.