【问题标题】:Decoding COMP-3 packed fields in an ASCII file in Python?在 Python 中解码 ASCII 文件中的 COMP-3 压缩字段?
【发布时间】:2015-05-27 18:22:33
【问题描述】:

我有一个以前是 EBCDIC 编码文件的文件,它使用 dd 转换为 ASCII。但是,有些行包含我想阅读的 COMP-3 压缩字段。

例如,我要解码的其中一行的字符串表示形式是:

'15\x00\x00\x00\x04@\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x0c777093020141204NNNNNNNNYNNNN\n'

我要读取的字段由PIC S9(09) COMP-3 POS. 3指定,即从第三个字节开始的字段,解码时长九个字节(因此,编码时长五字节,根据@987654322 @)。

我了解 COMP-3 规范,并且我也知道对于这个特定的行,该字段的整数值应该是 315,但我不知道要做什么才能真正解码该字段。我也不确定使用dd 将文件转换为 ASCII 是否存在问题。

以前有没有人处理过类似的问题,或者有什么明显的我遗漏的东西?谢谢!

【问题讨论】:

    标签: python ebcdic comp-3


    【解决方案1】:

    经过多次反复试验,我注意到,直接编码为 Ascii 格式会产生正确的数字,除了最后一个数字和符号。有一个转换表可以对最后一位进行转换。 这是我使用一些适用于我的用例的快速而肮脏的代码所做的。 我的文件已加载到 pandas 中的数据框中,我正在调用此函数通过传入值和小数位数为我进行翻译。

    sign = {'{': 1,'A': 1,'B': 1,'C': 1,'D': 1,'E': 1,'F': 1,'G': 1,'H': 1,'I': 1,'}': -1,'J': -1,'K': -1,
    'L': -1,'M': -1,'N': -1,'O': -1,'P': -1,'Q': -1,'R': -1 }
    
    last_digit = {'{': 0,'A': 1,'B': 2,'C': 3,'D': 4,'E': 5,'F': 6,'G': 7,'H': 8,'I': 9,'}': 0,'J': 1,'K': 2,
    'L': 3,'M': 4,'N': 5,'O': 6,'P': 7,'Q': 8,'R': 9 }
    
    def unpack(value,decimal):
    
        l = value.str[-1:]
        s = l.map(sign)
        d = l.map(last_digit)
        num = value.str[:-1]
        return (num.apply(int)*10+d)*s/10**decimal
    

    现在您在数据框中的新字段可以是:

    df['unpacked'] = unpack(df['Packed'],2)
    

    【讨论】:

    • 这适用于常规签名字段,而不是 COMP-3 压缩字段。
    【解决方案2】:

    如果进行逆向字符编码转换,则可能的值可以确定;因为有 [很好的理由] 对此表示怀疑,所以最好的做法是按照 Bill Woodger 的建议,以 text 格式获取数据的新副本,或者获取原始数据,但不会使用固有的二进制 [部分]数据的字符翻译破坏数据。在这种特定情况下,我相信该值是可确定的;但作为 0d377 (+377) 而不是 0d315 (+315)。
    希望可以理解以下几点:

    ASCII 字符串(给定\xEncoded):

    '15\x00\x00\x00\x04@\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x0c777093020141204NNNNNNNNYNNNN\n'
    

    ASCII(十六进制):

      ....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+
    X'31350000000440000000000C000000000C3737373039333032303134313230344E4E4E4E4E4E4E4E594E4E4E4E0A'
               -04-    ASCII x04->x37 in EBCDIC [control character End of Transmission (EOT)]
                 -40-  ASCII x40->x7C in EBCDIC [or xB5 or x80 or xEC or ?? per @ is a variant character in EBCDIC]
    

    EBCDIC:

      ....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+
    x'F1F5000000377C000000000C000000000CF7F7F7F0F9F3F0F2F0F1F4F1F2F0F4D5D5D5D5D5D5D5D5E8D5D5D5D525'
               -37-    EBCDIC x37->x04 in ASCII [control character End of Transmission (EOT)]
                 -7C-  EBCDIC x7C->x40 in ASCII [or A7 or 25 or ?? per x7C does not represent an invariant character in EBCDIC]
    

    PIC S9(09) COMP-3 POS. 3 中的数据字节是压缩二进制编码十进制 (BCD),从位置 5 到 14 的五个字节 [在所示的刻度线中;十进制数字000000377C],表示正十进制整数值377。我毫不怀疑,那是原始值。

    偶然地,对于该特定字符串,从 EBCDIC 到 ASCII 的转换并未因无法往返字符转换而损坏。记录中接下来的两个值也可能定义相同,并且在与 EBCDIC 之间的转换中,这些值也不受数据丢失的影响;即代码点为 x0C 的控制字符在 EBCDIC 和 ASCII 中是相同的,并且都具有正零的十进制值。

    虽然可能有其他可能的代码页可供尝试往返,但 CP00037 提供了强有力的竞争者 [x7C 具有有效的符号半字节] 和有效的转换; 315 的值似乎不太可能,因为 保留 EBCDIC 控制字符 x31 必须转换为 ASCII x04 而不是 x91 或 xBA,并且最有可能的 EBCDIC x5C 莫名其妙地必须转换转换为 ASCII x40 而不是转换为 x2A [或作为负值 x5D 莫名其妙地转换为 ASCII x40 而不是转换为 x29;没有考虑任何非首选的标牌可能性],这两者都没有任何意义。

    【讨论】:

      【解决方案3】:

      是的,文件包含非字符数据并且已在文件或记录级别从 EBCDIC 转换为 ASCII 是一个问题。使用什么工具来做到这一点不是问题。

      到目前为止,对您来说最简单的事情是请求仅以字符形式向您提供数据。如果数据包含带符号的字段,则符号应该是单独的,如果有隐含的小数位,这些应该是实际的,或由缩放值指示(以您更方便的为准)。

      那么你不需要转换任何东西。我永远无法理解人们如何认为他们可以只给您包含“whatever”的 EBCDIC 数据并期望您对其进行整理。

      如果您单击 EBCDIC 标记,您会发现一些其他解决方案,如果由于某些愚蠢的原因,无法从 EBCDIC 源获得字符数据,您可以应用这些解决方案。既然他们已经给你废话了,他们可能会想出一些愚蠢的理由。如果是这样,请(礼貌地)把它记录下来给你的老板。

      如果你得到字符数据,那么你可以 dd 或其他任何东西来转换它(如果你仍然得到看起来很有趣的东西,检查代码页)。

      如果您转换非字符数据,事情会被腌制的原因如下:

      05  a-packed-decimal-positive-five COMP-3 PIC S9 VALUE +5.
      05  a-character-asterisk PIC X VALUE "*".
      

      在 EBCDIC 中,这两者都具有十六进制值 5C。两者都将转换为 ASCII 星号。 COMP-3 的值 5 随即丢失。请注意,COMP-3 可以在低位符号之外为其每个字节取任意一对数字。碰巧碰到控制角色时腌制。 “二进制”字段也是如此,确实更糟糕,因为意外命中的可能性更大。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-22
        • 2019-05-07
        • 2023-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-27
        • 1970-01-01
        相关资源
        最近更新 更多