При работе со смешанными форматами, которые повторяются и имеют известный фиксированный размер, часто проще сначала разбить строку,
Быстрый пример будет:
binary.scan(/.{LENGTH_OF_DATA}/).map { |item| item.unpack(FORMAT) }
Рассматривая приведенный выше пример, возьмите длину строки, включая символ табуляции (в байтах), плюс размер 3-х чисел. Если ваши строки буквально 'ABCDEF\t'
, вы должны использовать размер 19 (7 для строки, 12 для 3-х чисел).
Ваш конечный продукт будет выглядеть так:
str.scan(/.{19}/).map { |item| item.unpack('P7fff') }
За пример:
irb(main):001:0> ary = ["ABCDEF\t", 3.4, 5.6, 9.1, "FEDCBA\t", 2.5, 8.9, 3.1]
=> ["ABCDEF\t", 3.4, 5.6, 9.1, "FEDCBA\t", 2.5, 8.9, 3.1]
irb(main):002:0> s = ary.pack('pfffpfff')
=> "\xE8Pd\xE4eU\x00\x00\x9A\x99Y@33\xB3@\x9A\x99\x11A\x98Pd\xE4eU\x00\x00\x00\x00 @ff\x0EAffF@"
irb(main):003:0> s.unpack('pfffpfff')
=> ["ABCDEF\t", 3.4000000953674316, 5.599999904632568, 9.100000381469727, "FEDCBA\t", 2.5, 8.899999618530273, 3.0999999046325684]
Незначительные различия в точности неизбежны, но не стоит об этом беспокоиться, поскольку они проистекают из разницы 32-разрядных чисел с плавающей запятой и 64-разрядных двойных (то, что Ruby использовал внутри), а разница точности будет меньше имеет значение для 32-разрядного числа с плавающей запятой.