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

2024-09-30 06:28:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试移植一些Delphi代码,将数据发送到Universe数据库。为了使文本易读的数据库,我们需要在原始设备制造商编码它。你知道吗

在Delphi中是这样做的:

    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]);

然后我们就这样翻译我们的文本

    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;

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


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中转换为以下字节:

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

(a)转换为“”,即十六进制的chr(160)或0xA0。éis'''或chr(130),0x82在hexa中,íis''',char(161)或0xA1在hexa中,依此类推)

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

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')

通过这个,我得到以下字节:

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

我的问题是,这种原始设备制造商编码使用不可打印的字符,如在'É'=chr(144)(0x90在十六进制)。如果我尝试用数组调用bytes(txt_registro,'cp1252'),其中我将'É'翻译成chr(0x90),我会得到以下错误:

caracteres_mal = 'Éü'
txt_registro = convertir_string_a_universe(txt_orig)
datos = bytes(txt_registro, 'cp1252')

  File "C:\Users\Hector\PyCharmProjects\pyuniverse\pyuniverse\UniverseRegister.py", line 138, in reconstruir_registro_universe
    datos = bytes(txt_registro, 'cp1252')
  File "C:\Users\Hector\AppData\Local\Programs\Python\Python36-32\lib\encodings\cp1252.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character '\x90' in position 0: character maps to <undefined>

如何在不引发此UnicodeEncodeError的情况下执行此OEM编码?你知道吗


Tags: intxt编码stringvalueuvbeginregistro
1条回答
网友
1楼 · 发布于 2024-09-30 06:28:44

这是因为cp1252不知道chr(0x90)。如果你试着用utf-8来代替,它会工作的。你知道吗

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

我不明白你为什么要转换成cp1252:你已经应用了一个自定义的转换映射,然后用bytes(txt_registro, 'cp1252'),你又将结果转换成cp1552。你知道吗

我想你想要的是:

datos = bytes(txt_orig, 'uv')

其中uv是cutom编解码器。你知道吗

因此,您必须为它编写一个编码器和一个解码器(这基本上是您已经完成的工作)。看看https://docs.python.org/3/library/codecs.html#codecs.register 注册新的编解码器。您将向其注册的函数应该返回文档中上面描述的CodecInfo对象。你知道吗

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')

编辑

编码器/解码器函数应该返回字节,因此需要更新convertir_string_a_universe一点。你知道吗

相关问题 更多 >

    热门问题