【问题标题】:Regular expression to return string split up respecting nested parentheses正则表达式返回字符串拆分尊重嵌套括号
【发布时间】:2022-01-24 17:16:43
【问题描述】:

我知道关于如何根据括号拆分字符串的问题存在很多答案,但它们从不递归地这样做。 查看字符串1 2 3 (test 0, test 0) (test (0 test) 0):
正则表达式 \s(?![^\(]*\)) 返回 "1", "2", "3", "(test 0, test 0)", "(test", "(0 test) 0)"
我正在寻找的正则表达式将返回
"1", "2", "3", "(test 0, test 0)", "(test (0 test)0)"

"1", "2", "3", "test 0, test 0", "test (0 test)0"
这将让我再次递归地在结果中使用它,直到没有括号。
理想情况下,它也会尊重转义的括号,但我本人在正则表​​达式方面并不是那么先进,只知道基础知识。
有没有人知道如何处理这个问题?

【问题讨论】:

  • 是什么让您认为regex 是解决此问题的正确工具?
  • 当字符串的组成部分具有语义价值时,例如平衡括号,最好进行标记和解析。正则表达式可以是您的词法分析器/标记器的一个组件,但并不是完成整个工作的最佳选择。
  • 当我们知道上下文/背景时,选择一个可持续的解决方案通常会有所帮助:这些由数字和括号组成的字符串表达式来自哪里?它们代表什么?

标签: python regex


【解决方案1】:

仅将regex 用于该任务可能有效,但并不简单。

另一种可能性是编写一个简单的算法来跟踪字符串中的括号:

  1. 在所有括号处拆分字符串,同时返回分隔符(例如使用re.split
  2. 保持一个计数器跟踪括号:start_parens_count 用于(end_parens_count 用于)
  3. 使用计数器,在空白处拆分或将当前数据添加到临时变量 (term)
  4. 当最左边的括号关闭时,将term 附加到值列表并重置计数器/临时变量。

这是一个例子:

import re

string = "1 2 3 (test 0, test 0) (test (0 test) 0)"


result, start_parens_count, end_parens_count, term = [], 0, 0, ""
for x in re.split(r"([()])", string):
    if not x.strip():
        continue
    elif x == "(":
        if start_parens_count > 0:
            term += "("
        start_parens_count += 1
    elif x == ")":
        end_parens_count += 1
        if end_parens_count == start_parens_count:
            result.append(term)
            end_parens_count, start_parens_count, term = 0, 0, ""
        else:
            term += ")"
    elif start_parens_count > end_parens_count:
        term += x
    else:
        result.extend(x.strip(" ").split(" "))


print(result)
# ['1', '2', '3', 'test 0, test 0', 'test (0 test) 0']

不是很优雅,但很有效。

【讨论】:

  • 解析算法是一种可靠的方法,并与富有表现力的代码一起很好地解释了。
【解决方案2】:

你可以使用pip install regex并使用

import regex
text = "1 2 3 (test 0, test 0) (test (0 test) 0)"
matches = [match.group() for match in regex.finditer(r"(?:(\((?>[^()]+|(?1))*\))|\S)+", text)]
print(matches)
# => ['1', '2', '3', '(test 0, test 0)', '(test (0 test) 0)']

请参阅online Python demo。请参阅regex demo。 正则表达式匹配:

  • (?: - 非捕获组的开始:
    • (\((?>[^()]+|(?1))*\)) - 任何嵌套括号之间的文本
  • | - 或
    • \S - 任何非空白字符
  • )+ - 小组结束,重复一次或多次

【讨论】:

  • 你的意思是最后一个量词在非捕获组内吗?
  • @oriberu 不,但你的建议看起来像(\((?>[^()]+|(?1))*\))|\S+
  • 我想知道,因为量化整个表达式不应该改变你的结果,而量化非空白组允许它匹配多个字符(假设非括号序列可能不止一个字符很长,即使那不在测试数据中)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-14
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多