在Python中将EBCDIC编码解码为ASCII/可读文本

3
我有一个编码为'cp500'的IBM大型机文件(我被告知),需要解码为ASCII或可读文本。该文件从Unix服务器获取并使用IPSwitch工具传输到Windows。
我已经尝试了以下代码,但无法实现我想要的结果:
sample data = 'ðñðòðõÅäù@@@@@@@ððð :BÄÑðò÷øò@@@JaÈK' - in txt file

import codecs

with open(file, "rb") as ebcdic:
    ascii_txt = codecs.decode(ebcdic, "cp500")
    print(ascii_txt)

这是产生类型错误。
"TypeError: decoding with 'cp500' codec failed (TypeError: a bytes-
like object is required, not '_io.BufferedReader')"

然后我试了这两个。
with open(file, 'r', encoding='cp500') as f:
    for line in f:
        print(line)

with codecs.open(file, 'r', encoding='cp500')
    for line in f:
        print(line)

我也尝试使用国际编码格式"cp1140"。
with open(file, 'r', encoding="cp1140") as f:
    for line in f:
       print(line)

我期望有一个可读的输出 - 一个像这样的复制簿布局...
0001***********
0002...........
0003...........

但是以上三个都打印输出为:
C¢C£C¢C¥C¢C§CeCuC¾       C¢C¢C¢âCdCjC¢C¥C¼C½C¥   [/Ch.

我也尝试以“rb”模式读取文件:
with open(file, 'rb') as f:
    for line in f:
        print(line)

这将会产生以下输出:
b'\xc3\xb0\xc3\xb1\xc3\xb0\xc3\xb2\xc3\xb0\xc3\xb5\xc3\x85\xc3\xa4\xc3\xb9@@@@@@@\xc3\xb0\xc3\xb0\xc3\xb0 :B\xc3\x84\xc3\x91\xc3\xb0\xc3\xb2\xc3\xb7\xc3\xb8\xc3\xb2@@@Ja\xc3\x88K'

这是我第一次处理EBCDIC /主机文件-希望能得到解码方面的任何帮助!

提前致谢 :)


这个看起来像是正确解码了吗:"010205EU9 000\x80\x9aâDJ02782 [/H."?它不是ASCII码(它包含0x7f以上的控制码和带重音的字符),但它大部分是可读的字符。 - lenz
1个回答

3
我猜测EBCDIC数据是用Latin-1解码,并以UTF-8保存在你现在使用的TXT文件中。
让我们试着用你示例的简略版本进行重构:
>>> copybook = '0102 [/H.'

以下是原始内容:

这段文字使用EBCDIC进行编码:

>>> '0102 [/H.'.encode('cp500')
b'\xf0\xf1\xf0\xf2@Ja\xc8K'

这是原始大型机文件中写入的字节序列。你也可以用一般(非Python)表示方式来写:

F0 F1 F0 F2 40 4A 61 C8 4B

现在这些字节被使用Latin-1或者可能是CP-1252("Windows Latin-1")解码了。 如果你在Windows机器上执行此操作,就会发生这样的情况:

>>> with open(file) as f:
...     text = f.read()
>>> text
'ðñðò@JaÈK'

您可以通过以下方式模拟这种错误编码情况:
>>> '0102 [/H.'.encode('cp500').decode('latin1')
'ðñðò@JaÈK'

这是你在帖子开头展示的字符串。 这已经比处理大型机文件的纯粹问题更糟糕 - 它是一个大型机文件的乱码!

现在,让事情变得更糟的是,该字符串使用UTF-8保存到文件中。 我们也来尝试一下:

>>> '0102 [/H.'.encode('cp500').decode('latin1').encode('utf8')
b'\xc3\xb0\xc3\xb1\xc3\xb0\xc3\xb2@Ja\xc3\x88K'

根据上一个片段(其中你以'rb'模式打开并打印输出),这些是包含在您的TXT文件中的字节。

现在这些字节不再是有效的EBCDIC编码了。使用Latin-1和UTF-8进行编码往返失真了内容:

>>> '0102 [/H.'.encode('cp500').decode('latin1').encode('utf8').decode('cp500')
'C¢C£C¢C¥ [/Ch.'

这是你在问题中展示的首次尝试所得到的输出。

为了从这种情况中恢复,你需要撤消扭曲:

>>> distorted = '0102 [/H.'.encode('cp500').decode('latin1').encode('utf8')
>>> distorted
b'\xc3\xb0\xc3\xb1\xc3\xb0\xc3\xb2@Ja\xc3\x88K'
>>> recovered = distorted.decode('utf8').encode('latin1').decode('cp500')
>>> recovered
'0102 [/H.'

...或者在从文件中读取时,您可以让open为您执行第一步解码:

>>> with open(file, encoding='utf8') as f:
...     data = f.read()
...     text = data.encode('latin1').decode('cp500')

对于完整的示例行,这将产生以下文本:

'010205EU9       000\x80\x9aâDJ02782   [/H.'

我不能百分之百确认这是原始文本。 它包含一些控制字符(809A)和一个非ASCII字母(“â”)。 也许000...782块需要被解释为二进制blob。 但我希望这个分析能够帮助你更进一步解决这个问题!


非常感谢您的解释,但我也不确定我得到的文件是否被正确编码了。等我明天回到工作岗位再检查一下。 - Harinie R
80, 9A 可能是一个 Comp-3(二进制字段)。你需要改变你的方法——以字节为单位读取。Stringray 可能会做你想要的事情——不过我不确定它的状态如何。 - Bruce Martin
@BruceMartin 我也会尝试使用Stringray.....而且Lenz,看起来文件已经被正确编码,并且每个字段都有一个布局.....所以现在我需要在任何情况下对其进行解码....让我更深入地研究一下,有疑问再回来! - Harinie R
2
@HarinieR 如果你的文件确实像最后一个例子中展示的那样(b'\xc2\xb0...'),那么你肯定有双重编码的数据。EBCDIC编码的文本几乎不可能用UTF-8解码。 - lenz
@HarinieR,你解决了上述问题吗?我需要做类似的事情。 - Ramandeep Mehmi
@RamandeepMehmi 不,我的文件已经正确编码,然后继续进行,因为源加密存在问题。 - Harinie R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接