是否可以使用 Python 的 re 模块一次性检索一组任意无序的命名组?

StackOverflow https://stackoverflow.com/questions/2187931

  •  25-09-2019
  •  | 
  •  

这对于某些问题来说非常方便:

>>> re.search('(?P<b>.b.).*(?P<i>.i.)', 'abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

但如果我不知道提前会收到什么订单怎么办?

[更新]

例如,假设我有一个输入变量,其中包含一些未知顺序的字符,而“b”恰好位于“i”之后。我仍然希望能够参考“ .b”的组。和我。'无需根据输入var中的订单订购我的正则命令。所以,我希望我能做这样的事情,但我不知道是否可能:

>>> re.search('(?P<b>.b.)|(?P<i>.i.)', unknown_order_alphabet_str).groupdict()
{'i': 'hij', 'b': 'abc'}

[更新结束]

我四处搜寻,绞尽脑汁,但找不到任何好的线索。猜测这个功能不会存在,因为 re 执行此操作的唯一方法可能是为每个组扫描一次整个字符串(当然我可以在循环中执行此操作),但我想我会看到 stackoverflow 大脑的内容不得不说一下。

感谢您的帮助,
乔什

有帮助吗?

解决方案

使用竖线(“或”)的RE模式,finditer让所有感兴趣的匹配对象:每次都会有groupdict为没有参与那场比赛组值None,你可以“合并“的类型的字典根据自己的喜好。

例如:

import re

def mergedgroupdict(pattern, thestring):
  there = re.compile(pattern)
  result = {}
  for mo in there.finditer(thestring):
    d = mo.groupdict()
    for k in d:
      if k not in result and d[k] is not None:
        result[k] = d[k]
  return result

此使用合并策略这仅仅是挑第一实际匹配图案中的每一个命名的基团。现在例如

>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')
{'i': 'hij', 'b': 'abc'}
>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'[::-1])
{'i': 'jih', 'b': 'cba'}

想必你的愿望,如果我正确地解释你的问题。

其他提示

>>> [m.groupdict() for m in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]

似乎做工精细,但如果你有很多组检查哪一次不是None可能得到乏味。

此查找所有.b.和字符串中的所有.i.匹配。如果你想确保它一经发现每一个你必须手动检查这一点。

我可以得到最接近的是这样的:

>>> [match.groupdict() for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]

您如何结合的字典,然后取决于是否你希望不止一个匹配。如果你只想要一个相互匹配,你可以这样做:

>>> results = {}
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'):
...     results.update(dict((k,v) for k, v in match.groupdict().iteritems() if v is not None))
... 
>>> results
{'i': 'hij', 'b': 'abc'}

或者对于多个匹配:

>>> results = defaultdict(lambda: [])
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijkabcdefghijk'):
...     for k, v in match.groupdict().iteritems():
...         if v is not None:
...             results[k].append(v)
... 
>>> results
defaultdict(<function <lambda> at 0x7f53d0992c08>, {'i': ['hij', 'hij'], 'b': ['abc', 'abc']})

这是一种不需要的方法 finditer 也不字典合并:

>>> pat = re.compile(r'(?:.*?(?:(?P<b>.b.)|(?P<i>.i.))){2}')

>>> pat.search('abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

>>> pat.search('aicdefghbjk').groupdict()
{'i': 'aic', 'b': 'hbj'}

这是假设每个角色 bi 在字符串中只出现一次,否则:

  • 如果其中一个字符可能丢失,您可以使用 {,2} 代替 {2}.
  • 如果其中一个字符出现多次,搜索将检索该字符的前两次出现 任何一个 其中(例如它可以找到 b 两次都没有找到 i 根本没有)。

下面是一种后来者的游戏在一个滑动,这是可读的初学者也:

>>> dict([(name, re.search(pattern, "abcdefghijk").group())
          for name, pattern in {"b": ".b.", "i": ".i"}.items()])  
{'b': 'abc', 'i': 'hij'}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top