4

我的文件包含 45 个十六进制数字,由空格分隔或 48 个十六进制数字,由空格分隔。我需要所有这些数字单独而不是整体。我目前正在使用蛮力方法来获得 45 个数字。

pattern = re.compile("([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s([0-9a-f]{2})\s")

但是,即使这样,我仍然无法弄清楚如何在 48 十六进制数字实例中提取剩余的三个数字。你能帮我简化这个问题吗?

我会避免像下面这样的解决方案(如果它有效则没有尝试过),因为我稍后将不得不为每个实例拆分字符串,即考虑到它可以提供正确的输出!

(((?:[0-9a-f]{2})\s){48})|(((?:[0-9a-f]{2})\s){45})

谢谢!

4

6 回答 6

7

编写长 RE 时,请考虑使用re.VERBOSE使它们更具可读性。

pattern = re.compile(r"""
 ^( [0-9a-fA-F]{2} (?: \s [0-9a-fA-F]{2} ){44}
                (?:(?: \s [0-9a-fA-F]{2} ){3} )? )$ 
""", re.VERBOSE)

读作:两个十六进制数字,后跟 44 次(空格后跟两个十六进制数字),可选地后跟 3 次(空格后跟两个十六进制数字)。

测试:

>>> pattern.match(" ".join(["0f"] * 44))
>>> pattern.match(" ".join(["0f"] * 45))
<_sre.SRE_Match object at 0x7fd8f27e0738>
>>> pattern.match(" ".join(["0f"] * 46))
>>> pattern.match(" ".join(["0f"] * 47))
>>> pattern.match(" ".join(["0f"] * 48))
<_sre.SRE_Match object at 0x7fd8f27e0990>
>>> pattern.match(" ".join(["0f"] * 49))

最后,要检索单个数字,请.group(0).split()在匹配结果上执行。这比编写一个将所有数字分成不同组的 RE 要容易得多。

编辑:好的,这是解决原始问题的方法。只需动态构建 RE。

chunk = r"""([0-9a-fA-F]{2}\s)"""
pattern = re.compile(chunk * 45 + "(?:" + chunk * 3 + ")?")
于 2012-09-25T13:31:19.067 回答
5

使用两种模式不是更容易吗?这样您就不需要复杂的逻辑来处理子组。

pattern1 = re.compile("([0-9a-f]{2}\s){45}")
pattern2 = re.compile("([0-9a-f]{2}\s){48}")
于 2012-09-25T13:21:24.180 回答
4

我相信您可能正在寻找的是re.findall

取决于该字符串的其余部分的外观..这对我有用,可以让我获得每个十六进制的字符串列表

import re
reg = re.compile("[0-9a-f]{2}\s")
hexes = "ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12 ab 12"
hexList = re.findall(reg, hexes)

这将为您提供所有 2 个字符十六进制的列表。从那里将其拆分为 45/48 是微不足道的,具体取决于您从中获取的字符串中的其他类型的数据。

但是,如果字符串中有大量数据,这将不起作用。

或者,虽然你说你不想这样做,但做这样的事情确实很简单:

reg = re.compile("([0-9a-f]{2}\s){45,48}") #Edit: Missed an open paren
match = reg.search(hexes)
if match:
    splitList = match.group().split()

然后你有一个所有数字的列表,很好地分开。

于 2012-09-25T13:40:31.237 回答
1

我喜欢你的硬连线方法(即满足你的特定需求),但我会通过乘法生成模式字符串。我的示例需要 3 人一组和 5 人一组(只是为了更容易测试):

pattern = re.compile(r'(?:' +
  r'\s+'.join([ r'([a-f0-9]{2})' ] * 5) +
  r')|(?:' +
  r'\s+'.join([ r'([a-f0-9]{2})' ] * 3) +
  r')')
m1 = pattern.match('ab cd ef')
m2 = pattern.match('ab cd ef 34 56')

结果m.groups()将类似于(None, None, None, None, None, 'ab', 'cd', 'ef')3('ab', 'cd', 'ef', '34', '56', None, None, None)组和 5 组。因此您可以检查是否m.groups()[0]为 None 以找到您获得的版本(45 或 48),然后使用 groups()[:48] 或组()[48:]。

确保在较小的数字 (45) 之前有较大的数字 (48)。

如果您有办法知道一个十六进制数组的结束位置和下一个组的开始位置,则此模式当然可以与findallsearch、或类似方法一起使用。finditer在这个例子中,十六进制数之间的空格必须是空格或制表符,其他东西(如换行符)将十六进制数组彼此分开:

pattern = re.compile(r'(?:' +
  r'[ \t]+'.join([ r'([a-f0-9]{2})' ] * 5) +  # replaced \s by [ \t]
  r')|(?:' +
  r'[ \t]+'.join([ r'([a-f0-9]{2})' ] * 3) +
  r')')
print [ i.groups() for i in pattern.finditer(
    'ab cd ef 34 56\nab cd ef 34 56\nab cd ef\nab cd ef\n') ]

→</p>

[ ('ab', 'cd', 'ef', '34', '56', None, None, None),
  ('ab', 'cd', 'ef', '34', '56', None, None, None),
  (None, None, None, None, None, 'ab', 'cd', 'ef'),
  (None, None, None, None, None, 'ab', 'cd', 'ef') ]
于 2012-09-25T14:10:22.677 回答
0

可以考虑使用re.findall吗?

>>> import re
>>> pat = r'([0-9A-Fa-f]+)'
>>> s= '45f 567B 45C67'
>>> for i in re.findall(pat, s):
    print i


45
567B
45C67

使用此方法,无论您的文件中有多少个数字。

于 2012-09-25T13:17:12.213 回答
0

如果您知道该文件包含十六进制数据,只需将整个文件读入一个字符串,然后将其拆分为空格。这适用于 45、48 或任何其他数字。

import re
splitter = re.compile('\s+')
data = splitter.split(file(filename,'r').read())
于 2012-09-25T13:31:08.993 回答