解码使用CP437表编码的文件

时间:2019-10-18 20:24:04

标签: python unicode utf-8 decode encode

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

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

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

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

此外,如果UTF-8 0和1s的长度大于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]))

1 个答案:

答案 0 :(得分:0)

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

#!/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所在的位置进行替换。