CP437 控制字符解码是否损坏?

问题描述 投票:0回答:3

根据代码页 437 的维基百科页面,字节值

\x01
\x1f
应解码为图形字符,例如
b'\x01'
等于 ☺
'\u263A'
。但这不是
decode
产生的:

>>> b'\x01'.decode('cp437')
'\x01'

Python 3.6 是这样,但 2.7 对于所有 31 字节值也是如此。

python character-encoding
3个回答
4
投票

虽然存在与字节范围

\x01
\x1f
相关的图形,但这些图形仅在某些上下文中使用。在其他上下文中,这些代码点将被解释为控制字符,如 ASCII 中那样。引用 CP437 上的 IBM 页面

代码点 X'01' 到 X'1F' 和 X'7F' 可能是控件或图形,具体取决于上下文。显示内存映射中的十六进制代码 视频显示缓冲区是一个图形。对于打印机,图形上下文是由数据流中的前面的控制序列建立的。那里有两个 这样的控制序列:ESC X'5C'和ESC X'5E'分别命名为“打印所有字符”和“打印单个字符”。其他情况下的代码 有问题的点用作对照。

Python 的 CP437 解码基于 Unicode.org 上的 Unicode 映射,它使用控制字符解释。

Unicode 常见问题解答意味着“CP437 和其他 DOS 类型代码页的特殊图形字符(01-1F、7F)的正确 Unicode 映射”应在 https://www.unicode.org/ 上提供Public/MAPPINGS,但深入挖掘只会发现带有控制字符的映射,以及链接到几个 IBM 网站的 page。深入研究 IBM 的站点会发现 ftp://ftp.software.ibm.com/software/globalization/gcoc/attachments/CP00437.txt,它根据 IBM 的

GCGID 给出了 
\x01
-
\x1f 的图形映射系统,但不是 Unicode。

我不知道是否真的有is来自IBM或Unicode的官方映射,它根据CP437的图形解释给出了

\x01
-
\x1f
的规范Unicode映射。


1
投票

我设法在那里找到这个文件:
https://unicode.org/Public/MAPPINGS/VENDORS/MISC/IBMGRAPH.TXT

它包括 Unicode 字符 (0x01-0x1f) 到 IBM CP437 以及 IBM CP864(阿拉伯语)的映射。


1
投票

是的,它坏了。

不,还没有人将此作为错误提交给 PSF。可能没有人会这样做,原因有二:

首先,有几个不明确的字符(确切地说,Microsoft 没有实现“IBM Codepage 437”),并且 PSF 可能不愿意对其中任何一个做出决定:

  • b'\x07'
    代表 Bell 或 Bullet
  • b'\x08'
    代表退格键或倒转项目符号
  • b'\x09'
    代表水平制表符或白色圆圈
  • b'\x0a'
    代表回车或反白圆圈
  • b'\x0d'
    代表换行或八分之一音符/音乐音符

其次,代码页 437 现在实际上从未被使用过,因为 CPython 3.6 在 Windows 上添加了一个不可见的 UTF-16 控制台 I/O。 如果您想将代码页

x-microsoft-437
用于您自己的目的(例如,编写与

type
一起使用时可以正确呈现的文本文件,或者在 Windows 上的 PyPy 上执行 Unicode I/O),这里有一个保守的方法代码片段(它将所有 5 个不明确的字符实现为控制字符,这正是 Windows CMD 实现它的方式)您可以添加到您自己的代码中:
"""https://stackoverflow.com/questions/46942721"""

# -*- filename: _site_codecs/x_microsoft_437.py -*-

# Remember that sys.stdin.reconfigure() cannot be called after any input has been read
# So if you're using this for I/O, please call that ONLY in __main__ after appropriate checks
# https://stackoverflow.com/questions/77808931

import codecs
import encodings
from encodings import cp437 as _psf_cp437


def _cp437_search_function(encoding):
    if encodings.normalize_encoding(encoding) == encodings.normalize_encoding(_Cp437CodecInfo.name):
        return _Cp437CodecInfo
    return None

codecs.register(_cp437_search_function)


class _Cp437Codec(codecs.Codec):
    # https://github.com/python/cpython/blob/v3.12.1/Lib/encodings/cp437.py#L9
    def encode(self,input,errors='strict'):
        return codecs.charmap_encode(input,errors,_cp437_encoding_map)
    def decode(self,input,errors='strict'):
        return codecs.charmap_decode(input,errors,_cp437_decoding_map)

class _Cp437IncrementalEncoder(codecs.IncrementalEncoder):
    def encode(self, input, final=False):
        return codecs.charmap_encode(input,self.errors,_cp437_encoding_map)[0]

class _Cp437IncrementalDecoder(codecs.IncrementalDecoder):
    def decode(self, input, final=False):
        return codecs.charmap_decode(input,self.errors,_cp437_decoding_map)[0]

class _Cp437StreamWriter(_Cp437Codec,codecs.StreamWriter):
    pass

class _Cp437StreamReader(_Cp437Codec,codecs.StreamReader):
    pass

_Cp437CodecInfo = codecs.CodecInfo(
    # https://github.com/python/cpython/blob/v3.12.1/Lib/encodings/cp437.py#L34
    name='x-microsoft-437',
    encode=_Cp437Codec().encode,
    decode=_Cp437Codec().decode,
    incrementalencoder=_Cp437IncrementalEncoder,
    incrementaldecoder=_Cp437IncrementalDecoder,
    streamreader=_Cp437StreamReader,
    streamwriter=_Cp437StreamWriter,
)


_cp437_encoding_map = _psf_cp437.encoding_map | {
  0x263a: 0x01,
  0x263b: 0x02,
  0x2665: 0x03,
  0x2666: 0x04,
  0x2663: 0x05,
  0x2660: 0x06,
  0x2642: 0x0b,
  0x2640: 0x0c,
  0x266b: 0x0e,
  0x263c: 0x0f,
  0x25ba: 0x10,
  0x25c4: 0x11,
  0x2195: 0x12,
  0x203c: 0x13,
  0x00b6: 0x14,
  0x00a7: 0x15,
  0x25ac: 0x16,
  0x21a8: 0x17,
  0x2191: 0x18,
  0x2193: 0x19,
  0x2192: 0x1a,
  0x2190: 0x1b,
  0x221f: 0x1c,
  0x2194: 0x1d,
  0x25b2: 0x1e,
  0x25bc: 0x1f,
  0x2302: 0x7f,
}


_cp437_decoding_map = _psf_cp437.decoding_map | {
  0x01: 0x263a,
  0x02: 0x263b,
  0x03: 0x2665,
  0x04: 0x2666,
  0x05: 0x2663,
  0x06: 0x2660,
  0x0b: 0x2642,
  0x0c: 0x2640,
  0x0e: 0x266b,
  0x0f: 0x263c,
  0x10: 0x25ba,
  0x11: 0x25c4,
  0x12: 0x2195,
  0x13: 0x203c,
  0x14: 0x00b6,
  0x15: 0x00a7,
  0x16: 0x25ac,
  0x17: 0x21a8,
  0x18: 0x2191,
  0x19: 0x2193,
  0x1a: 0x2192,
  0x1b: 0x2190,
  0x1c: 0x221f,
  0x1d: 0x2194,
  0x1e: 0x25b2,
  0x1f: 0x25bc,
  0x7f: 0x2302
}


© www.soinside.com 2019 - 2024. All rights reserved.