Преобразование двоичной информации в обычный тип данных без внешних модулей в Python - PullRequest
1 голос
/ 28 марта 2010

Мне поручено прочитать плохо отформатированный двоичный файл и принять переменные. Хотя мне нужно сделать это на C ++ (особенно ROOT), я решил сделать это на python, потому что python имеет для меня смысл, но я планирую заставить его работать на python, а затем заняться перезаписью на C ++ поэтому использование простых в использовании модулей Python не поможет мне в дальнейшем.

В основном я делаю это:

In [5]: some_value
Out[5]: '\x00I'

In [6]: ''.join([str(ord(i)) for i in some_value])
Out[6]: '073'

In [7]: int(''.join([str(ord(i)) for i in some_value]))
Out[7]: 73

И я знаю, что имеет , чтобы быть лучше. Что ты думаешь?

EDIT:

Немного информации о двоичном формате.

альтернативный текст http://grab.by/3njm альтернативный текст http://grab.by/3njv альтернативный текст http://grab.by/3nkL

Это тест с порядком байтов, который я использую:

# Read a uint32 for endianess
endian_test = rq1_file.read(uint32)
if endian_test == '\x04\x03\x02\x01':
    print "Endian test: \\x04\\x03\\x02\\x01"
    swapbits = True
elif endian_test == '\x01\x02\x03\x04':
    print "Endian test: \\x01\\x02\\x03\\x04"
    swapbits = False

Ответы [ 5 ]

2 голосов
/ 28 марта 2010

Ваш int(''.join([str(ord(i)) for i in some_value])) работает ТОЛЬКО когда все байты, кроме последнего, равны нулю. Примеры:
'\x01I' должно быть 1 * 256 + 73 == 329; вы получите 173
'\x01\x02' должно быть 1 * 256 + 2 == 258; вы получите 12
'\x01\x00' должно быть 1 * 256 + 0 == 256; вы получите 10

Это также основывается на предположении, что целые числа хранятся в бигендовском стиле; Вы подтвердили это предположение? Вы уверены, что '\x00I' представляет целое число 73, а не целое 73 * 256 + 0 == 18688 (или что-то еще)? Позвольте нам помочь вам подтвердить это предположение, сообщив нам, какую марку и модель компьютера и какую операционную систему использовали для создания данных.

Как представлены отрицательные целые числа?

Вам нужно иметь дело с числами с плавающей точкой ?

Является ли требование написать его на C ++ неизменным? Что означает "(ROOT, в частности)"?

Если единственным диктатом является здравый смысл, предпочтительный порядок будет:

  1. Напишите это на Python, используя модуль struct.

  2. Напишите его на C ++, но используйте подпрограммы библиотеки C ++ (особенно, если используется плавающая точка). Не изобретай велосипед заново.

  3. Сверните свои собственные процедуры преобразования в C ++. Вы можете получить копию источника C для структурного модуля Python .

Обновление

Комментарии после публикации информации о формате файла:

  1. Маркер порядка байтов, по-видимому, необязателен, за исключением начала файла. Это хитроумно; он основан на том факте, что если его там нет, 3-й и 4-й байты блока являются первыми 2 байтами строки заголовка, и ни '\x03\x04', ни '\x02\x01' не могут правильно запустить строку заголовка. Умнее всего было бы прочитать SIX байтов - если первые 4 - это маркер байтов, следующие два - это длина заголовка, а следующее чтение - для строки заголовка; в противном случае ищите назад 4 байта, затем читайте строку заголовка.

  2. Выше в категории неприятности. Отрицательные размеры вызывают серьезную обеспокоенность, поскольку в них указывается МАКСИМАЛЬНАЯ длина, и нет упоминания о том, как определяется ФАКТИЧЕСКАЯ длина. Там написано: «Фактический размер записи задается построчно». Как? Нет документации о том, как выглядит «строка данных». В описании много раз упоминаются «строки»; заканчиваются ли эти строки возвратом каретки и / или переводом строки? Если так, как можно определить разницу между, скажем, байтом перевода строки и первым байтом, скажем, uint16, который принадлежит текущей «строке» данных? Если нет перевода строки или что-то еще, как узнать, когда закончится текущая строка данных? Есть ли размер uintNN перед каждой переменной или ее частью?

  3. Тогда говорится, что (2) выше (отрицательный размер) также относится к строке заголовка. Разум поражает. Есть ли у вас примеры (в документации по разметке файлов или в реальных файлах) "отрицательного размера" (а) строки заголовка (б) "строки данных"?

  4. Является ли этот «определенный формат» общедоступным, например, документация в сети? У формата есть имя для поиска? Вы уверены, что вы первый человек в мире, который хочет прочитать этот формат?

  5. Чтение этого формата файла, даже с полной спецификацией, не является тривиальным упражнением, даже для опытного в двоичном формате человека, который также имеет опыт работы с Python (у которого BTW не имеет float128). Сколько человеко-часов было выделено для выполнения задачи? Каковы штрафы за (а) задержку (б) неудачу?

  6. Ваш первоначальный вопрос заключался в исправлении вашего интересного способа разбора uint16 - делать гораздо больше - это выходит за рамки / цели того, что представляют собой вопросы SO.

2 голосов
/ 28 марта 2010
import struct
result, = struct.unpack('>H', some_value)
2 голосов
/ 28 марта 2010

Вы в основном вычисляете «число в базе 256», которое является полиномом, поэтому по методу Хорнера:

>>> v = 0
>>> for c in someval: v = v * 256 + ord(c)

Более типичным было бы использование эквивалентных битовых операций, а не арифметики - эквивалент следующего:

>>> v = 0
>>> for c in someval: v = v << 8 | ord(c)
1 голос
/ 28 марта 2010

Эквивалентом модуля Python struct является C struct и / или union, поэтому бояться его использовать глупо.

0 голосов
/ 28 марта 2010

Я не совсем уверен, какой формат данных вы хотите извлечь, но, возможно, вам лучше написать пару универсальных служебных функций для извлечения нужного вам типа данных:

def int1b(data, i):
   return ord(data[i])

def int2b(data, i):
   return (int1b(data, i) << 8) + int1b(data, i+1)

def int4b(data, i):
   return (int2b(data, i) << 16) + int2b(data, i+2)

С помощью таких функций вы можете легко извлекать значения из данных, а также довольно легко переводить их в C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...