从Ruby中的二进制文件中提取十六进制字符串

时间:2019-01-05 23:35:43

标签: ruby binary-data data-extraction

对于二进制文件,我想提取绿色(日期和小时)和蓝色的十六进制字符串。蓝色的十六进制字符串介于字节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 :(得分:1)

为了获取以 @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/app/**",).permitAll(); } 开始并以20结尾的字节,您需要像这样更改正则表达式:

00

基本上,我仅将正则表达式的最后一部分从next unless line =~ /(.{8}2d.{4}2d.{4})20(.{4}3a.{4}3a.{4})|^20(.*?0?)0{2}/ 更改为(^20.*)。 这是解释:

  • 从20开始-^20(.*?0?)0{2}
  • 尽可能少地匹配-^20
  • 直到您获得两个连续的0 .*?
  • 0{2}之后的0?处理您拥有.*?的情况

我也不将X0 00包含在捕获的组中,因为无论如何您稍后都会在代码中删除它,因此您可以在其中删除20

.gsub(/20/, '')

答案 1 :(得分:1)

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::strptimeString#unpack

请注意,打印日期和时间都必须有效。例如,将跳过简单的正则表达式会接受的"0000-19-39 29:00:00"