Декодирование упакованных полей COMP-3 в файле ASCII в Python?

У меня есть файл, который раньше был в кодировке EBCDIC, но был преобразован в ASCII с помощью dd< /а>. Однако некоторые строки содержат упакованные поля 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, то есть поле, которое начинается с третьего байта и имеет длину девять байтов при декодировании (и, следовательно, пять байтов при кодировании, согласно спецификация COMP-3).

Я понимаю спецификацию COMP-3, и я также знаю, что для этой конкретной строки целочисленное значение этого поля должно быть 315, но я не могу понять, что делать, чтобы на самом деле декодировать поле. Я также не уверен, является ли проблемой тот факт, что файл был преобразован с помощью dd в ASCII.

Кто-нибудь работал над подобной проблемой раньше, или есть что-то очевидное, что я упускаю? Спасибо!


person user3873438    schedule 24.03.2015    source источник


Ответы (3)


Да, проблема заключается в том, что файл содержит несимвольные данные и был преобразован из 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, равное пяти, было потеряно. Обратите внимание, что COMP-3 может, за пределами младшего знака, принимать любую пару числовых цифр для каждого из своих байтов. Рассол, когда вы случайно наткнетесь на управляющего персонажа. То же самое для «двоичных» полей, хуже, потому что больше возможностей случайного попадания.

person Bill Woodger    schedule 04.04.2015

Если необходимо выполнить обратное преобразование кодировки символов, то значение может быть определено; поскольку есть [веские причины] сомневаться в этом, лучше всего сделать, как предложил Билл Вуджер, и получить новую копию данных в текстовом формате или получить новую копию исходные данные, но не повреждать данные с помощью преобразования символов изначально двоичных [частей] данных. В этом конкретном случае я уверен, что значение можно определить; но как 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), для пяти байтов с позиций с пятой по четырнадцатую [в показанных линиях шкалы; десять шестнадцатеричных цифр 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; какие-либо нежелательные возможности вывесок не рассматривались], ни один из них не имеет смысла.

person CRPence    schedule 20.05.2015

Я заметил, что при большом количестве проб и ошибок прямое кодирование в формат 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)
person SleepyJoe    schedule 22.08.2019
comment
Это относится к обычным полям со знаком, а не к упакованным полям COMP-3. - person spejsy; 12.12.2019