Извлечь шестнадцатеричные строки из двоичного файла в Ruby - PullRequest
0 голосов
/ 06 января 2019

для двоичного файла я хочу извлечь шестнадцатеричные строки зеленым (дата и час) и синим. Шестнадцатеричная строка синего цвета находится между байтами 09 и 00.

Мне удалось извлечь с помощью регулярного выражения дату и час и частично шестнадцатеричную строку синим цветом. Для этого я установил в качестве «разделителя строк» ​​байт 09 (\ x09)

Возможно, проблему можно решить с помощью регулярного выражения, чтобы получить строку между 09 и 00, но в настоящее время с моим регулярным выражением (^ 20. *) я получаю нежелательные и не ascii байты. Может кто-нибудь помочь мне получить байты только между 09 и 00.

Мой текущий код:

BEGIN{  $/="\x09".force_encoding("BINARY")   }

IO.foreach("file.dat"){ |l|

    line = l.unpack('H*')[0]
    next unless line =~ /(.{8}2d.{4}2d.{4})20(.{4}3a.{4}3a.{4})|(^20.*)/

        if ( $1 != nil and $2 != nil )
            date = $1
            hour = $2
            p date.gsub(/../) { |b| b.hex.chr }
            p hour.gsub(/../) { |b| b.hex.chr } 
        end

        if $3 != nil            
            p $3.gsub(/20/,"").gsub(/../) { |b| b.hex.chr }         
        end 
}

Токовый выход

"2017-10-19"
"15:43:27"
"83492624790981030E100000\x00\x18\v\x16\x84\x13\x05$B#q\x000\x03\x81\x01\n\x00\x00v\x00\x0000000003\t"
"2017-12-05"
"09:32:15"
"001104059419632801001B237100300381010A0000\x00\x00\x00\x00\x02\xD0\x00\x00\x00\b\xFEF\xCC\x00\x06\xE7\f\x13\x0F+\e\xB5\xE1/\x00\xB5\x83I&$y\t"
=> nil

Ожидаемый результат

"2017-10-19"
"15:43:27"
"83492624790981030E100000"
"2017-12-05"
"09:32:15"
"001104059419632801001B237100300381010A0000"
=> nil

Файл выглядит так: enter image description here

Прикрепленный образец файла: file.dat

Ответы [ 2 ]

0 голосов
/ 06 января 2019
require 'date'

IN_FNAME = "file.dat"
OUT_FNAME = "out_file.dat"
END_OF_LINE = "\x09"

str_out = ''
File.foreach(IN_FNAME, sep=END_OF_LINE) do |line|
  dt_str = line[3..21]
  if (DateTime.strptime(dt_str, '%Y-%m-%d %H:%M:%S') rescue nil)
    puts dt_str.split(' ')
    next
  end
  arr = line.unpack("C*")
  next unless arr.first == 32
  a = arr.map(&:chr).select { |c| c.match? /\d/ }
  puts a.join
  str_out << a.map(&:ord).pack("C*")    
end
2017-10-19
15:43:27
83492624790981030100000000000003
2017-12-05
09:32:15
0011040594196328010012371003003810100000

Последний шаг - записать двоичный файл OUT_FNAME.

File.binwrite(OUT_FNAME, str_out)
  #=> 72

Как видно, записано 72 байта. Вот скриншот этого файла при просмотре в шестнадцатеричном редакторе.

enter image description here

Это можно сравнить со снимком экрана, показанным в вопросе.

Мы можем прочитать этот файл, чтобы убедиться, что он был написан правильно.

File.binread(OUT_FNAME)
  #=> "834926247909810301000000000000030011040594196328010012371003003810100000"

См. DateTime :: strptime и String # unpack .

Обратите внимание, что для печати даты и времени оба значения должны быть действительными. Например, "0000-19-39 29:00:00", которое будет принято простым регулярным выражением, будет пропущено.

0 голосов
/ 06 января 2019

Чтобы получить байты, начинающиеся с 20 и заканчивающиеся 00, необходимо изменить регулярное выражение следующим образом:

next unless line =~ /(.{8}2d.{4}2d.{4})20(.{4}3a.{4}3a.{4})|^20(.*?0?)0{2}/

В основном я изменил только последнюю часть регулярного выражения с (^20.*) на ^20(.*?0?)0{2}. Вот объяснение:

  • начиная с 20 - ^20
  • соответствует как можно меньше - .*?
  • пока вы не доберетесь до двух последовательных 0с 0{2}
  • 0? после .*? обрабатывает случай, когда у вас есть X0 00

Также я не включаю 20 в захваченную группу, так как вы все равно удаляете его позже в коде, так что вы можете удалить .gsub(/20/, '') в

p $3.gsub(/20/,"").gsub(/../) { |b| b.hex.chr }         
...