【问题标题】:Decoding a file that is encoded using CP437 table解码使用 CP437 表编码的文件
【发布时间】:2020-02-15 20:31:43
【问题描述】:

我必须编写一个程序来解码文件(使用 CP437 编码),方法是根据 CP437 表替换每个符号的 Unicode,然后将其转换为 UTF-8 并将输出打印到文件中。

我有两个文件 - 一个输入文件包含一个长文本,其中包含普通字符和一些奇怪的字符(在结果文件中,这些奇怪的字符将被各种破折号替换),以及一个包含 256 行对的 CP437 文件(第一部分是十进制数,第二部分是Unicode,例如73 0049)。

这就是我试图解决这个问题的方法:

  1. 使用“RB”标志打开输入文件
  2. 由于我使用“RB”打开文件,我将每个符号读取为字节,然后将其存储在“文本”列表中
  3. 读完文件后,循环浏览文本列表
  4. 在循环过程中,我得到了符号的十进制值
  5. 我使用十进制值从 CP437.txt 文件中获取 Unicode
  6. 我将 Unicode 转换为 0 和 1
  7. 我将 Unicode 的二进制表示形式转换为 UTF-8 和 返回 0 和 1
  8. 我将那些 UTF-8 0 和 1 转换为字节并将它们写入 使用“WB”标志打开的结果文件

另外,如果 UTF-8 0 和 1 的长度超过 8 个,那么我将每 8 个字符拆分一次,然后将它们转换为字节(我不确定这是否正确)

主要问题是当我尝试编写结果时,我得到了很多乱码,我不确定问题出在哪里。感谢您提供任何帮助,我已经被这个任务困住了一段时间,只是无法弄清楚问题出在哪里。

def convertBinToHex(binary):
    binToHex = hex(int(binary, 2))
    temp = list(binToHex)
    temp = temp[2:]
    binToHex = "".join(temp).upper()
    return binToHex


def convertUnicodeToUTF(unicodeBin, symbolDecimal, returnBin):
    # https://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16
    bytesCount = 0
    if int("0000", 16) <= symbolDecimal <= int("007F", 16):
        if returnBin:
            return unicodeBin
        return convertBinToHex(unicodeBin)
    elif int("0080", 16) <= symbolDecimal <= int("07FF", 16):
        bytesCount = 2
    elif int("0800", 16) <= symbolDecimal <= int("FFFF", 16):
        bytesCount = 3
    elif int("10000", 16) <= symbolDecimal <= int("10FFFF", 16):
        bytesCount = 4
    else:
        return

    if bytesCount == 2:
        template = ['1', '1', '0', 'x', 'x', 'x', 'x', 'x', '1', '0', 'x', 'x', 'x', 'x', 'x', 'x']
    elif bytesCount == 3:
        template = ['1', '1', '1', '0', 'x', 'x', 'x', 'x', '1', '0', 'x', 'x', 'x', 'x', 'x', 'x', '1', '0', 'x', 'x',
                    'x',
                    'x', 'x', 'x']
    elif bytesCount == 4:
        template = ['1', '1', '1', '1', '0', 'x', 'x', 'x', '1', '0', 'x', 'x', 'x', 'x', 'x', 'x', '1', '0', 'x', 'x',
                    'x',
                    'x', 'x', 'x', '1', '0', 'x', 'x', 'x', 'x', 'x', 'x']
    else:
        return

    results = []
    unicodeList = list(unicodeBin)
    counter = len(unicodeList) - 1

    for el in reversed(template):
        if el == 'x':
            if counter >= 0:
                results.append(unicodeList[counter])
                counter -= 1
            else:
                results.append('0')
        elif el == '0':
            results.append('0')
        else:
            results.append('1')

    results.reverse()
    results = "".join(results)

    if returnBin:
        return results
    else:
        return convertBinToHex(results)



codePage = {}
with open("CP437.txt") as f:
    for line in f:
        (key, val) = line.split()
        codePage[key] = val

text = []

with open("386intel.txt", 'rb') as f:
    while True:
        c = f.read(1)
        if c:
            # Converts bytes to bits (string)
            text.append("{:08b}".format(int(c.hex(), 16)))
        if not c:
            print("End of file")
            break


bytesString = 0
bytesStringInt = 0
resultFile = open("rez.txt", "wb")

for item in text:
    decimalValue = int(item, 2)
    newUnicode = codePage[str(decimalValue)]
    unicodeToBin = "{0:08b}".format(int(newUnicode, 16))
    bytesString = convertUnicodeToUTF(unicodeToBin, decimalValue, True)
    if len(bytesString) > 8:
        bytesStringSplit = [bytesString[i:i + 8] for i in range(0, len(bytesString), 8)]
        for x in bytesStringSplit:
            bytesStringInt = int(x, 2)
            resultFile.write(bytes([bytesStringInt]))
            # print(bytes([bytesStringInt]))
    else:
        bytesStringInt = int(bytesString, 2)
        resultFile.write(bytes([bytesStringInt]))
        # print(bytes([bytesStringInt]))

【问题讨论】:

    标签: python unicode utf-8 decode encode


    【解决方案1】:

    未测试,因为您忽略了提供输入文件:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use autodie;
    
    my @cp;
    {
        open my $fh, '<', 'CP437.txt';
        while (my $line = readline $fh) {
            chomp $line;
            my ($k, $v) = split ' ', $line;
            $cp[$k] = chr hex $v;
        }
    }
    {
        open my $in, '<:raw', '386intel.txt';
        open my $out, '>:encoding(UTF-8)', '386intel.txt.utf8';
        while (my $line = readline $in) {
            $out->print(
                join '',            # 5. join characters into string
                map {               # 2. loop over octets
                    $cp[            # 4. look up character corresponding to
                                        # octet numeric value
                        ord         # 3. numeric value of octet
                    ]
                }
                split '', $line     # 1. split line into octets
            );
        }
    }
    

    该程序非常容易理解,只需 10 行重要代码(如果需要,还可以轻松移植到 Python)。


    如果文件CP437.txt符合标准,那么它就变成了:

    › piconv -f CP437 -t UTF-8 < 386intel.txt > 386intel.txt.utf8
    

    如果分配确实涉及手动编码为 UTF-8 而不是使用库,则在代码中 chr 函数所在的位置替换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      • 2018-12-27
      • 2019-02-04
      • 2014-04-23
      • 2011-10-07
      • 1970-01-01
      相关资源
      最近更新 更多