正则表达式获取二进制内容之间的字节

时间:2019-01-26 07:17:05

标签: ruby regex byte

我有以下3个包含二进制数据的字符串。

s1="\t 28890\tABGT\tXYZW\t 94 23 08 92 00 00 00 EC 02 10 00 E2 00 4B\t\x00\x00\x00\x00\x01\f".force_encoding("ASCII-8BIT")
s2=" \t0000013\t123\t9886\t 95 83 49 26 0E 82 00 A6 08 02 06 C0\x00\x00\x00\x00\x02\xB2\x00\x00\x00\x00\b\xFEF".force_encoding("ASCII-8BIT")
s3=" \t0000013\t123\t9HN3\t 95 83 49 26 0E 82 00 A6 08 02 06 C0\xA1\x02\x00\x00\x02\xB2\b\xFEF".force_encoding("ASCII-8BIT")

我有以下3个类似的正则表达式来获取*\t和以\开头的内容(即\ t,\ x00,\ xB2,\ xFEF)之间的字节

s1[/(?<=[A-Z]{4}\t ).+?(?=\t)/]
s2[/(?<=[0-9]{4}\t ).+?(?=\x00)/]
s3[/(?<=.+\t ).+?(?=\x..)/]

前2个正则表达式适用于字符串s1和s2,但是更通用的正则表达式如何匹配这3种情况?

我尝试了正则表达式s3[/(?<=.+\t ).+?(?=\x..)/],但下面出现错误。

irb(main):> s1[/(?<=[A-Z]{4}\t ).+?(?=\t)/]
=> "94 23 08 92 00 00 00 EC 02 10 00 E2 00 4B"

irb(main):> s2[/(?<=[0-9]{4}\t ).+?(?=\x00)/]
=> "95 83 49 26 0E 82 00 A6 08 02 06 C0"

irb(main):> s3[/(?<=.+\t ).+?(?=\x..)/]
SyntaxError: (irb):4953: invalid hex escape
s3[/(?<=.+\t ).+?(?=\x..)/]
                    ^
invalid pattern in look-behind: /(?<=.+\t ).+?(?=..)/
        from /usr/bin/irb:11:in `<main>'

我认为我只需要正确的正则表达式,或者有更好的方法可以在不使用正则表达式的情况下提取所需的值?

感谢您的帮助

2 个答案:

答案 0 :(得分:2)

R = /\h{2}(?: \h{2})+/

def extract(str)
  str[R]
end

extract(s1)
  #=> "94 23 08 92 00 00 00 EC 02 10 00 E2 00 4B" 
extract(s2)
  #=> "95 83 49 26 0E 82 00 A6 08 02 06 C0" 
extract(s3)
  #=> "95 83 49 26 0E 82 00 A6 08 02 06 C0" 

正则表达式为:“匹配两个十六进制数字(\h{2}),后跟一个空格,后跟两个十六进制数字,这三个字符作为一个组匹配一次或多次(+),{ {1}}是一个非捕获组

答案 1 :(得分:2)

#ruby 2.3.1 

xs = ["\t 28890\tABGT\tXYZW\t 94 23 08 92 00 00 00 EC 02 10 00 E2 00 4B\t\x00\x00\x00\x00\x01\f".force_encoding("ASCII-8BIT"),
      " \t0000013\t123\t9886\t 95 83 49 26 0E 82 00 A6 08 02 06 C0\x00\x00\x00\x00\x02\xB2\x00\x00\x00\x00\b\xFEF".force_encoding("ASCII-8BIT"),
      " \t0000013\t123\t9HN3\t 95 83 49 26 0E 82 00 A6 08 02 06 C0\xA1\x02\x00\x00\x02\xB2\b\xFEF".force_encoding("ASCII-8BIT"),
      "\t 28890\tABGT\tXYZW\t 94\t\x00\x00\x00\x00\x01\f".force_encoding("ASCII-8BIT"),
      " \t0000013\t123\t9HN3\t 95 83 49 26 0E 82 00 A6 08 02 06 C0".force_encoding("ASCII-8BIT")]

r = /
    (?<=                  # start of lookbehind: asserts that what immediately precedes the current position in the string are
      [[:alnum:]]{4}\t[ ] # a space character, and a tab character and then four alphanumeric characters
    )                     # end of lookbehind
    [[:xdigit:]]{2}       # match two hex digits
    (?:                   # start non-capture group
      [ ]                 # match a space character
      [[:xdigit:]]{2}     # match two hex digits
    )*                    # end the non-capture group and match it zero or more times
    /x                    # free-spacing mode

xs.map { |x| p x[r] }

输出:

"94 23 08 92 00 00 00 EC 02 10 00 E2 00 4B"
"95 83 49 26 0E 82 00 A6 08 02 06 C0"
"95 83 49 26 0E 82 00 A6 08 02 06 C0"
"94"
"95 83 49 26 0E 82 00 A6 08 02 06 C0"