在Python中用ASCII文件解码COMP-3打包字段?

时间:2015-03-24 12:28:25

标签: python ebcdic comp-3

我有一个以前是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指定,即,以第三个字节开头并且在解码时长度为9个字节的字段(因此,在编码时长度为5个字节,根据COMP-3 spec)。

我理解COMP-3规范,我也知道对于这个特定的行,该字段的整数值应该是315,但我无法弄清楚要做什么才能实际解码字段。我也不确定文件是否使用dd转换为ASCII这一事实是否存在问题。

之前有没有人处理过类似的问题,或者有什么东西显而易见我错过了吗?谢谢!

3 个答案:

答案 0 :(得分:1)

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

到目前为止,最简单的方法是请求仅以字符形式提供给您的数据。如果数据包含有符号的字段,则符号应该是单独的,并且如果有隐含的小数位,则这些应该是实际的,或者用缩放值表示(以更方便的为准)。

然后你需要转换任何东西。我永远无法理解人们怎么认为他们可以给你包含“无论什么”的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可以在低位符号之外,为其每个字节取任何数字对。碰巧碰到控制角色的时候。对于“二进制”字段也是如此,更糟糕的是因为更多意外命中的可能性。

答案 1 :(得分:0)

如果要执行反向字符编码转换,则可以确定值 ;因为[有充分的理由]怀疑这种效果,最好的办法就是比尔伍德建议并以 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;没有考虑任何非优选的标志可能性],这两者都没有任何意义。

答案 2 :(得分:0)

经过很多次反复试验,我注意到,直接编码为Ascii格式将得到正确的数字,但最后一位数字和符号除外。有一个转换表可以转换最后一位数字。 这是我用一些适用于我的用例的快速而肮脏的代码所做的事情。 我的文件以大熊猫的形式加载到数据帧中,我正在调用此函数来通过传递值和小数位数来为我进行翻译。

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)
相关问题