0

我一直在尝试使用 PCRE 中的正则表达式从以下字符串中获取单独的组:

drop = blah blah blah something keep = bar foo nlah aaaa rename = (a=b d=e) obs=4 where = (foo > 45 and bar == 35)

我试图做的小组是这样的:

1. drop = blah blah blah something
2. keep = bar foo nlah aaaa
3. rename = (a=b d=e)
4. obs=4
5. where = (foo > 45 and bar == 35)

我已经使用递归编写了一个正则表达式,但由于某种原因,递归在选择多个单词之后部分起作用,drop就像它只选择前 3 个单词(blah blah blah)而不是第 4 个单词。我查看了各种 stackoverflow 问题,并尝试过使用积极的前瞻,但这是我能达到的最接近的,现在我被卡住了,因为我无法理解我做错了什么。

我写的正则表达式:(?i)(drop|keep|where|rename|obs)\s*=\s*((\w+|\d+)(\s+\w+)(?4)|(\((.*?)\)))

同样可以在这里看到:RegEx Demo

感谢您对此提供任何帮助或了解我做错了什么。

4

2 回答 2

2

您可以使用较新的regex模块DEFINE

(?(DEFINE)
    (?<key>\w+)
    (?<sep>\s*=\s*)
    (?<value>(?:(?!(?&key)(?&sep))[^()=])+)
    (?<par>\((?:[^()]+|(?&par))+\))
)
(?P<k>(?&key))(?&sep)(?P<v>(?:(?&value)|(?&par)))

在 regex101.com 上查看演示


Python可能是:

import regex as re

data = """
drop = blah blah blah something keep = bar foo nlah aaaa rename = (a=b d=e) obs=4 where = (foo > 45 and bar == 35)
"""

rx = re.compile(r'''
(?(DEFINE)
    (?<key>\w+)
    (?<sep>\s*=\s*)
    (?<value>(?:(?!(?&key)(?&sep))[^()=])+)
    (?<par>\((?:[^()]+|(?&par))+\))
)

(?P<k>(?&key))(?&sep)(?P<v>(?:(?&value)|(?&par)))''', re.X)

result = {m.group('k').strip(): m.group('v').strip()
          for m in rx.finditer(data)}

print(result)

和产量

{'drop': 'blah blah blah something', 'keep': 'bar foo nlah aaaa', 'rename': '(a=b d=e)', 'obs': '4', 'where': '(foo > 45 and bar == 35)'}
于 2020-09-15T08:02:21.063 回答
1

您可以使用分支重置组解决方案:

(?i)\b(drop|keep|where|rename|obs)\s*=\s*(?|(\w+(?:\s+\w+)*)(?=\s+\w+\s+=|$)|\((.*?)\))

请参阅PCRE 正则表达式演示

细节

  • (?i)- 不区分大小写模式
  • \b- 单词边界
  • (drop|keep|where|rename|obs)- 第 1 组:组中的任何单词
  • \s*=\s*- 一个=包含 0+ 个空格字符的字符
  • (?|- 分支重置组的开始:
    • (\w+(?:\s+\w+)*)- 第 2 组:一个或多个单词字符后跟零个或多个重复一个或多个空格和一个或多个单词字符
    • (?=\s+\w+\s+=|$)- 最多一个或多个空格、一个或多个单词字符、一个或多个空格和=, 或字符串结尾
    • |- 或者
      • \((.*?)\)- (,然后第 2 组捕获除换行符之外的任何零个或多个字符,尽可能少,然后)
  • )- 分支重置组结束。

请参阅Python 演示

import regex
pattern = r"(?i)\b(drop|keep|where|rename|obs)\s*=\s*(?|(\w+(?:\s+\w+)*)(?=\s+\w+\s+=|$)|\((.*?)\))"
text = "drop = blah blah blah something keep = bar foo nlah aaaa rename = (a=b d=e) obs=4 where = (foo > 45 and bar == 35)"
print( [x.group() for x in regex.finditer(pattern, text)] )
# => ['drop = blah blah blah something', 'keep = bar foo nlah aaaa', 'rename = (a=b d=e)', 'obs=4', 'where = (foo > 45 and bar == 35)']
print( regex.findall(pattern, text) )
# => [('drop', 'blah blah blah something'), ('keep', 'bar foo nlah aaaa'), ('rename', 'a=b d=e'), ('obs', '4'), ('where', 'foo > 45 and bar == 35')]
于 2020-09-16T13:39:14.153 回答