如何修复UTF-8双编码XML文件

如何修复UTF-8双编码XML文件,xml,encoding,utf-8,Xml,Encoding,Utf 8,我有一个XML文件,它似乎由双编码UTF-8字符组成。例如,then hex dump中的“Gesch….ft”部分应为Geschäft: 00009f0: 4365 6c6c 3e3c 4861 7368 4365 6c6c 3e3c Cell><HashCell>< 0000a00: 5374 7220 7661 6c75 653d 2253 746f 7265 Str value="Store 0000a10: 735f 4d65 6e75 222f 3e3c

我有一个XML文件,它似乎由双编码UTF-8字符组成。例如,then hex dump中的“Gesch….ft”部分应为Geschäft:

00009f0: 4365 6c6c 3e3c 4861 7368 4365 6c6c 3e3c  Cell><HashCell><
0000a00: 5374 7220 7661 6c75 653d 2253 746f 7265  Str value="Store
0000a10: 735f 4d65 6e75 222f 3e3c 5374 7220 7661  s_Menu"/><Str va
0000a20: 6c75 653d 2247 6573 6368 c383 c2a4 6674  lue="Gesch....ft
0000a30: 6522 2f3e 3c2f 4861 7368 4365 6c6c 3e3c  e"/></HashCell><
0000a40: 4861 7368 4365 6c6c 3e3c 5374 7220 7661  HashCell><Str va
00009f0:4365 6c6c 3e3c 4861 7368 4365 6c6c 3e3c单元><
0000a00:5374 7220 7661 6c75 653d 2253 746f 7265 Str value=“存储
0000a10:735f 4d65 6e75 222f 3e3c 5374 7220 7661 s_菜单“/><

0000a40:4861 7368 4365 6c6c 3e3c 5374 7220 7661 HashCell>我找到了一种在UNIX上实现它的方法™. Z-Shell脚本中的以下四行将添加到它:

#!/bin/zsh
setopt No_Err_Exit
iconv -f "UTF-8" -t "ISO-8859-1" "${1}" >"${1}.new"
mv "${1}"       "${1}.old"
mv "${1}.new"   "${1}"

我想出了一个在UNIX上实现的方法™. Z-Shell脚本中的以下四行将添加到它:

#!/bin/zsh
setopt No_Err_Exit
iconv -f "UTF-8" -t "ISO-8859-1" "${1}" >"${1}.new"
mv "${1}"       "${1}.old"
mv "${1}.new"   "${1}"

假设双重编码只产生2字节的utf8序列(您可以为此添加检查),quick&dirty:

#include <stdio.h>
int main (void)
{
int state,ch;
unsigned val;

for(state = 0; ;  ) {
    ch = getc(stdin);
    if (ch==EOF) break;
    switch(state) {
    case 0:
            if ((ch & 0xe0) == 0xc0) {
                    val = (ch & 0x1f) << 6;
                    state = 1;
                    }
            else putc( ch, stdout);
            break;
    case 1:
            val |= (ch & 0x3f);
            putc(val, stdout);
            state = 0;
            break;
            }
    }
return 0;
}
#包括
内部主(空)
{
int状态,ch;
无符号val;
对于(状态=0;;){
ch=getc(标准偏差);
如果(ch==EOF)中断;
开关(状态){
案例0:
如果((ch&0xe0)=0xc0){
val=(ch&0x1f)gesel.out
$hextump-C gesel.in
00000000 47 65 73 65 6c c3 83 c2 a4 66 74 65 0a | Gesel…全职员工|
0000000天
$hextump-C gesel.out
00000000 47 65 73 65 6c c3 a4 66 74 65 0a | Gesel..fte|
0000000b

假设双重编码只产生2字节utf8序列(您可以添加一个检查),quick&dirty:

#include <stdio.h>
int main (void)
{
int state,ch;
unsigned val;

for(state = 0; ;  ) {
    ch = getc(stdin);
    if (ch==EOF) break;
    switch(state) {
    case 0:
            if ((ch & 0xe0) == 0xc0) {
                    val = (ch & 0x1f) << 6;
                    state = 1;
                    }
            else putc( ch, stdout);
            break;
    case 1:
            val |= (ch & 0x3f);
            putc(val, stdout);
            state = 0;
            break;
            }
    }
return 0;
}
#包括
内部主(空)
{
int状态,ch;
无符号val;
对于(状态=0;;){
ch=getc(标准偏差);
如果(ch==EOF)中断;
开关(状态){
案例0:
如果((ch&0xe0)=0xc0){
val=(ch&0x1f)gesel.out
$hextump-C gesel.in
00000000 47 65 73 65 6c c3 83 c2 a4 66 74 65 0a | Gesel…全职员工|
0000000天
$hextump-C gesel.out
00000000 47 65 73 65 6c c3 a4 66 74 65 0a | Gesel..fte|
0000000b

它不是双UTF-8编码-它是一个UTF-8文件,被解码为ISO-8859-1,然后保存在UTF-8 encoded.Aka.Mojibake中

要在Python中修复此问题,请执行以下操作:

import io
with io.open('mojibake.xml', 'r+', encoding='utf-8') as mojibaked_input_file:
    input_baked = mojibaked_input_file.read()
    # Reverse the wrong interpretation
    input_fixed = input_baked.encode('latin1').decode('utf-8')

    mojibaked_input_file.seek(0)
    mojibaked_input_file.truncate()
    mojibaked_input_file.write(input_fixed)

它不是双UTF-8编码的-它是一个UTF-8文件,被解码为ISO-8859-1,然后保存在UTF-8编码的.Aka.Mojibake中

要在Python中修复此问题,请执行以下操作:

import io
with io.open('mojibake.xml', 'r+', encoding='utf-8') as mojibaked_input_file:
    input_baked = mojibaked_input_file.read()
    # Reverse the wrong interpretation
    input_fixed = input_baked.encode('latin1').decode('utf-8')

    mojibaked_input_file.seek(0)
    mojibaked_input_file.truncate()
    mojibaked_input_file.write(input_fixed)

要删除双重编码,需要将文件从UTF-8转换为在第二次转换为utf8时错误用作源字符集的字符集

对于德语和其他西欧语言,最好使用“Windows-1252”或“CP1252”。它与Latin-1相同,只是它还有几个字符,并且在尝试转换为Latin-1时会产生错误

有几种工具可用于删除双重编码。在Mac和Linux上,默认情况下安装了
iconv
,因此您可以尝试

iconv -f utf8 -t cp1252 $YourFile > $NewFile
但是,如果文件也以BOM()开头,则可能会出现以下错误:

iconv: illegal input sequence at position 0
在这种情况下,请改用
uconv
,它接受大致相同的参数,但在文件开头处理BOM表:

uconv -f utf8 -t cp1252 $YourFile > $NewFile
在基于Debian的Linux发行版上,它附带

apt install icu-devtools
在Mac上,它可以与brew一起安装:

brew install icu4c

要删除双重编码,需要将文件从UTF-8转换为在第二次转换为utf8时错误用作源字符集的字符集

对于德语和其他西欧语言,最好使用“Windows-1252”或“CP1252”。它与Latin-1相同,只是它还有几个字符,并且在尝试转换为Latin-1时会产生错误

有几种工具可用于删除双重编码。在Mac和Linux上,默认情况下安装了
iconv
,因此您可以尝试

iconv -f utf8 -t cp1252 $YourFile > $NewFile
但是,如果文件也以BOM()开头,则可能会出现以下错误:

iconv: illegal input sequence at position 0
在这种情况下,请改用
uconv
,它接受大致相同的参数,但在文件开头处理BOM表:

uconv -f utf8 -t cp1252 $YourFile > $NewFile
在基于Debian的Linux发行版上,它附带

apt install icu-devtools
在Mac上,它可以与brew一起安装:

brew install icu4c

我该怎么做?使用哪种工具?使用哪种参数?-不回答,我自己想出来的。我在做…只是解码它(假设只有1字节和2字节序列),我该怎么做?使用哪种工具?使用哪种参数?-不回答,我自己想出来的。我在做…只是解码它(假设只有1字节和2字节序列)