Python字符串中的OEM不可打印字符

时间:2019-09-05 09:56:08

标签: python delphi encoding character-encoding delphi-7

我试图移植一些将数据发送到Universe数据库的Delphi代码。为了使数据库可以识别文本,我们需要在OEM中对其进行编码。

在Delphi中是这样完成的:

Error: Cycle: module.devcentralhub.azuread_service_principal.serviceprincipal, module.devcentralhub.azurerm_app_service.appservice, module.devcentralhub.azuread_application.appregistration

然后我们像这样简单地翻译文本

    procedure TForm1.GenerarTablasNLS;
    var
      i: integer;
    begin
      for i := 0 to 255 do
      begin
        TablaUV_NLS[i] := AnsiChar(i);
        TablaNLS_UV[i] := AnsiChar(i);   
      end;
      // Nulo final
      TablaUV_NLS[256] := #0;
      TablaNLS_UV[256] := #0;

      OemToCharA(@TablaUV_NLS[1], @TablaUV_NLS[1]);
      CharToOemA(@TablaNLS_UV[1], @TablaNLS_UV[1]);

我使用存储每个字符翻译的字典在Python中遵循相同的逻辑

    function StringToUniverse(const Value: string): AnsiString;
    var
      p: PChar;
      q: PAnsiChar;
    begin
      SetLength(Result, Length(Value));
      if Value = '' then Exit;

      p := Pointer(Value);
      q := Pointer(Result);
      while p^ <> #0 do
      begin
        q^ := TablaNLS_UV[Ord(AnsiChar(p^))];
        Inc(p);
        Inc(q);
      end;
    end;

只要我使用可打印字符进行翻译,此方法就可以“正常”运行。例如,字符串


class StringUniverseDict(dict):
    def __missing__(self, key):
        return key

TablaString2UV = StringUniverseDict()

def rellenar_tablas_codificacion():
    TablaString2UV['á'] = ' '       # chr(225) = chr(160)
    TablaString2UV['é'] = '‚'       # chr(233) = chr(130)
    TablaString2UV['í'] = '¡'       # chr(237) = chr(161)
    TablaString2UV['ó'] = '¢'       # chr(243) = chr(162)
    TablaString2UV['ú'] = '£'       # chr(250) = chr(163)
    TablaString2UV['ñ'] = '¤'       # chr(241) = chr(164)
    TablaString2UV['ç'] = '‡'       # chr(231) = chr(135)
    TablaString2UV['Á'] = 'µ'       # chr(193) = chr(181)
    TablaString2UV['É'] = chr(144)  # chr(201) = chr(144)     
    TablaString2UV['Í'] = 'Ö'       # chr(205) = chr(214)
    TablaString2UV['Ó'] = 'à'       # chr(211) = chr(224)
    TablaString2UV['Ñ'] = '¥'       # chr(209) = chr(165)
    TablaString2UV['Ç'] = '€'       # chr(199) = chr(128)
    TablaString2UV['ü'] = chr(129)  # chr(252) = chr(129)     

    TablaString2UV[chr(129)] = '_'  # chr(129) = chr(095)     
    TablaString2UV[chr(141)] = '_'  # chr(141) = chr(095)  
    TablaString2UV['•'] = chr(007)  # chr(149) = chr(007)  
    TablaString2UV['Å'] = chr(143)  # chr(197) = chr(143)     
    TablaString2UV['Ø'] = chr(157)  # chr(216) = chr(157)     
    TablaString2UV['ì'] = chr(141)  # chr(236) = chr(141)    

在Delphi中转换为以下字节:

"á é í ó ú ñ ç Á Í Ó Ú Ñ Ç"

(á转换为'',在hexa中为chr(160)或0xA0。é在'hexa'中是','或chr(130),0x82,在hexa中í是'¡',char(161)或0xA1等等)

在Python中,当我尝试将其编码为OEM时,请执行以下操作:

0xa0 0x20 0x82 0x20 0xa1 0x20 0xa2 0x20 0xa3 0x20 0xa4 0x20 0x87 0x20 0xb5 0x20 0xd6 0x20 0xe0 0x20 0xe9 0x20 0xa5 0x20 0x80 0xfe 0x73 0x64 0x73

然后,获取字节

def convertir_string_a_universe(cadena_python):
    resultado = ''
    for letra in cadena_python:
        resultado += TablaString2UV[letra]
    return resultado

这样我得到以下字节:

txt_registro = convertir_string_a_universe(txt_orig)
datos = bytes(txt_registro, 'cp1252')

我的问题是,此OEM编码使用了不可打印的字符,例如'É'= chr(144)(六进制为0x90)。如果我尝试使用我将'É'转换为chr(0x90)的数组调用字节(txt_registro,'cp1252'),则会出现此错误:

b'\xa0 \x82 \xa1 \xa2 \xa3 \xa4 \x87 \xb5 \xd6 \xe0 \xe9 \xa5 \x80 \x9a'

如何在不引发UnicodeEncodeError的情况下进行OEM编码?

1 个答案:

答案 0 :(得分:1)

这是因为cp1252不了解chr(0x90)。如果您尝试使用utf-8,它将起作用。

>>> chr(0x90).encode("utf8")
b'\xc2\x90'

我不明白您为什么尝试转换为cp1252:您已应用自定义转换图,然后使用bytes(txt_registro, 'cp1252')将结果再次转换为{{1} }。

我认为您正在寻找的东西是这样的:

cp1552

其中datos = bytes(txt_orig, 'uv') 是您的通用编解码器。

因此,您必须为此编写一个编码器和一个解码器(基本上这已经完成了)。看看https://docs.python.org/3/library/codecs.html#codecs.register 注册新的编解码器。您将向其注册的函数应返回文档上部的CodecInfo对象。

uv

编辑

编码器/解码器功能应返回字节,因此您需要稍微更新import codecs def buscar_a_uv(codec): if codec == "uv": return codecs.CodecInfo( convertir_string_a_universe, convertir_universe_a_string, name="uv") else: return None codecs.register(buscar_a_uv) datos = bytes(txt_orig, 'uv')