我正在处理使用UTF-8编码两次的遗留文件。例如,代码点ε
(U+03B5
)应该已经编码为CE B5
,而是编码为C3 8E C2 B5
(CE 8E
是UTF-8编码U+00CE
,C2 B5
是U+00B5
的UTF-8编码。
假设数据在CP-1252中进行编码,则执行了第二次编码。
要回到UTF-8编码,我使用以下(似乎错误的)命令
iconv --from utf8 --to cp1252 <file.double-utf8 >file.utf8
我的问题是iconv似乎无法转换回一些字符。更确切地说,iconv无法转换其UTF-8表示包含映射到CP-1252中的控制字符的字符的字符。一个例子是代码点ρ
(U+03C1
):
CF 81
,CF
被重新编码为C3 8F
,81
被重新编码为C2 81
。 iconv拒绝将C2 81
转换回81
,可能是因为它不知道如何精确映射该控制字符。
echo -e -n '\xc3\x8f\xc2\x81' | iconv --from utf8 --to cp1252
�iconv: illegal input sequence at position 2
如何在不关心映射的情况下告诉iconv执行数学UTF-8转换?
答案 0 :(得分:1)
echo -e -n '\xc3\x8f\xc2\x81' | iconv --from utf8 --to iso8859-1
Windows-1252与0x80-0x9F范围内的ISO-8859-1不同。例如,在您的情况下,ISO 8859-1中的0x81是U + 0081,但在Windows-1252中无效。
检查其余数据是否被误解为Windows-1252或ISO 8859-1。通常,ISO 8859-1更常见。
答案 1 :(得分:0)
以下代码使用Ruby的低级编码功能强制将双重编码的UTF-8(从CP1525)重写为普通的UTF-8。
#!/usr/bin/env ruby
ec = Encoding::Converter.new(Encoding::UTF_8, Encoding::CP1252)
prev_b = nil
orig_bytes = STDIN.read.force_encoding(Encoding::BINARY).bytes.to_a
real_utf8_bytes = ""
real_utf8_bytes.force_encoding(Encoding::BINARY)
orig_bytes.each_with_index do |b, i|
b = b.chr
situation = ec.primitive_convert(b.dup, real_utf8_bytes, nil, nil, Encoding::Converter::PARTIAL_INPUT)
if situation == :undefined_conversion
if prev_b != "\xC2"
$stderr.puts "ERROR found byte #{b.dump} in stream (prev #{(prev_b||'').dump})"
exit
end
real_utf8_bytes.force_encoding(Encoding::BINARY)
real_utf8_bytes << b
real_utf8_bytes.force_encoding(Encoding::CP1252)
end
prev_b = b
end
real_utf8_bytes.force_encoding(Encoding::BINARY)
puts real_utf8_bytes
它意味着在管道中使用:
cat $PROBLEMATIC_FILE | ./fix-double-utf8-encoding.rb > $CORRECTED_FILE