Декодирование файла, который закодирован с использованием таблицы CP437 - PullRequest
0 голосов
/ 18 октября 2019

Мне нужно написать программу для декодирования файла (который кодируется с использованием CP437), заменив Unicode каждого символа в соответствии с таблицей CP437, затем преобразовав его в UTF-8 и распечатав вывод в файл.

У меня есть два файла - входной файл, который содержит длинный текст с обычными и некоторыми странными символами (в файле результатов эти странные символы будут заменены различными черточками) и файл CP437, содержащий 256 строк пар (первая часть - десятичное число, вторая - Unicode, например, 73 0049).

Вот как я пытаюсь решить эту проблему:

  1. Откройтевходной файл с использованием флага 'RB'
  2. Поскольку я открываю файл с помощью 'RB', я считываю каждый символ в байтах, а затем сохраняю его в списке 'text'
  3. После того, как яЗакончив чтение файла, я перебираю текстовый список
  4. Во время цикла я получаю десятичное значение символа
  5. Я получаю Unicode из файла CP437.txt, используя десятичное числоvalue
  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):
    # /5839798/preobrazovanie-kodovyh-tochek-unicode-vruchnuy-v-utf-8-i-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 голосов
/ 19 октября 2019

Не проверено, поскольку вы не указали входные файлы:

#!/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.

...