【问题标题】:nested text in regular expressions正则表达式中的嵌套文本
【发布时间】:2016-08-24 15:10:06
【问题描述】:

我正在努力使用正则表达式。我无法让我的头脑围绕嵌套在较大文本中的类似文本。或许你能帮我理清思路。

这是一个示例测试字符串:

message msgName { stuff { innerStuff } } \n message mn2 { junk }

我想提取术语(例如,msgNamemn2)以及直到下一条消息之前的内容,以获得这样的列表:

消息名称 { 东西 { innerStuff } 更多东西 } mn2 {垃圾}'

我在过于贪婪或非贪婪地匹配以保留内括号但拆分更高级别的消息时遇到了麻烦。

这是一个程序:

import re
text = 'message msgName { stuff { innerStuff } more stuff } \n message mn2 { junk }'
messagePattern = re.compile('message (.*?) {(.*)}', re.DOTALL)
messageList = messagePattern.findall(text)
print "messages:\n"
count = 0
for message, msgDef in messageList:
    count = count + 1
    print str(count)
    print message
    print msgDef

它产生:

留言: 1 消息名称 东西 { innerStuff } 更多东西 } 消息 mn2 { 垃圾

这是我的下一次尝试,它使内部不贪婪:

import re
text = 'message msgName { stuff { innerStuff } more stuff } \n message mn2 { junk }'
messagePattern = re.compile('message (.*?) {(.*?)}', re.DOTALL)
messageList = messagePattern.findall(text)
print "messages:\n"
count = 0
for message, msgDef in messageList:
    count = count + 1
    print str(count)
    print message
    print msgDef

它产生:

留言: 1 消息名称 东西{innerStuff 2 mn2 垃圾

所以,我输了} more stuff }

我真的遇到了这个问题。有人能指出我正确的方向吗?我无法处理嵌套括号中的文本。关于工作正则表达式的建议或处理嵌套的类似文本的更简单示例会很有帮助。

【问题讨论】:

  • 我认为这个问题值得花一点时间在 mcve 上:stackoverflow.com/help/mcve
  • 那么,关键是要得到一个单词字符块,后面跟着一个平衡数的{....},对吧?像(\w+)\s*({(?>[^{}]++|(?2))*}) 这样的东西?要使用这种方法,您需要一个 PyPi 正则表达式模块。否则,编写一个解析器。或者 - 如果您确定只有一个嵌套级别,请使用解决方法:(\w+)\s*{[^{}]*(?:{[^{}]*}[^{}]*)*}(它可以与 re 模块一起使用)。
  • message (.*?) {(.*?)}(?: \\n|$) 会起作用吗?如果{}只有一层嵌套,也可以使用message (.*?) {(.*?(?:{[^}]*}).*?|.*?)}
  • ^^^ @WiktorStribiżew 哦,子模式递归,非常好!在阅读本文之前,我认为使用纯正则表达式没有完整的答案——技术上(在数学意义上)我是对的,因为递归子模式不是“常规的”!无论如何...我要说的是,如果您选择在代码中使用它,那么请包含一个有用的注释/函数名称来解释它的作用:P

标签: python regex python-2.7


【解决方案1】:

如果你可以使用PyPi regex module,你可以利用它的子程序调用支持:

>>> import regex
>>> reg = regex.compile(r"(\w+)\s*({(?>[^{}]++|(?2))*})")
>>> s = "message msgName { stuff { innerStuff } } \n message mn2 { junk }"
>>> print(reg.findall(s))
[('msgName', '{ stuff { innerStuff } }'), ('mn2', '{ junk }')]

正则表达式 - (\w+)\s*({(?>[^{}]++|(?2))*}) - 匹配:

  • (\w+) - 第 1 组匹配 1 个或多个字母数字/下划线字符
  • \s* - 0+ 个空格
  • ({(?>[^{}]++|(?2))*}) - 第 2 组匹配 {,后跟非 {} 或另一个平衡的 {...},由于 (?2) 子例程调用(递归整个第 2 组子模式),0 次或更多次,然后匹配结束}

如果只有一层嵌套,re 也可以使用

(\w+)\s*{[^{}]*(?:{[^{}]*}[^{}]*)*}

看到这个regex demo

  • (\w+) - 第 1 组匹配单词字符
  • \s* - 0+ 个空格
  • { - 左大括号
  • [^{}]* - 除了 {} 之外还有 0+ 个字符
  • (?:{[^{}]*}[^{}]*)* - 0+ 个序列:
    • {- 左大括号
    • [^{}]* - 除了 {} 之外还有 0+ 个字符
    • } - 右大括号
    • [^{}]* - 除了 {} 之外还有 0+ 个字符
  • } - 右大括号

【讨论】:

  • 维克托,非常感谢。这行得通,我学到了一些东西。
  • 太好了,这就是我们来这里的目的。 :) 我也学到了很多东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-18
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多