当前位置: 首页 > 知识库问答 >
问题:

是否可以在不使用递归或平衡组的情况下将嵌套括号与正则表达式匹配?

司寇照
2023-03-14

问题是:匹配一组任意嵌套的括号,这是一种正则表达式的风格,比如Java的Java。util。既不支持递归也不支持平衡组的正则表达式。即,匹配以下三个外部组:

(F(i(r(s)t)))((S)(e)((c)(o))(n)d) (((((((第三)))))))

这个练习纯粹是学术性的,因为我们都知道正则表达式不应该被用来匹配这些东西,就像Q-提示不应该被用来清洁耳朵一样。

堆栈

共有2个答案

淳于玺
2023-03-14

首先,您的输入不正确,因为有一个额外的括号(如下所示)

(F(i(r(s)t))) ((S)(e)((c)(o))n)d) (((((((Third)))))))
                                ^

进行适当的修改以包括或排除附加括号,最终可能会出现以下字符串之一:

删除了额外的括号

(F(i(r(s)t))) ((S)(e)((c)(o))n)d (((((((Third)))))))
                                ^

添加额外的括号以匹配额外的结束括号

((F(i(r(s)t))) ((S)(e)((c)(o))n)d) (((((((Third)))))))
^

其次,只有在包含递归功能的正则表达式中,这才是真正可能的,因为任何其他方法都不能正确匹配开/闭括号(如OP的解决方案所示,它匹配来自不正确输入的额外括号,如上所述)。

这意味着对于目前不支持递归的正则表达式风格(Java、Python、JavaScript等),正则表达式中的递归(或尝试模仿递归)是不可能的。

考虑到原始输入实际上是无效的,我们将使用以下输入进行测试。

(F(i(r(s)t))) ((S)(e)((c)(o))n)d) (((((((Third)))))))
(F(i(r(s)t))) ((S)(e)((c)(o))n)d (((((((Third)))))))
((F(i(r(s)t))) ((S)(e)((c)(o))n)d) (((((((Third)))))))

根据这些输入进行测试应得出以下结果:

  1. 无效(不匹配)
  2. 有效(匹配)
  3. 有效(匹配)

有多种方法可以匹配嵌套组。下面提供的解决方案都依赖于包含递归功能(例如PCRE)的正则表达式风格。

请参见此处使用的正则表达式

(?(DEFINE)
  (?<value>[^()\r\n]+)
  (?<groupVal>(?&group)|(?&value))
  (?<group>(?&value)*\((?&groupVal)\)(?&groupVal)*)
)
^(?&group)$

注意:这个正则表达式使用标志gmx

请参见此处使用的正则表达式

^(?<group>
  (?<value>[^()\r\n]+)*
  \((?<groupVal>(?&group)|(?&value))\)
  (?&groupVal)*
)$

注意:这个正则表达式使用标志gmx

请参见此处使用的正则表达式

^(?<group>(?<value>[^()\r\n]+)*\((?<groupVal>(?&group)|(?&value))\)(?&groupVal)*)$

请参见此处使用的正则表达式

^(([^()\r\n]+)*\(((?1)|(?2))\)(?3)*)$

注:这是我能想到的最短的方法。

我将解释最后一个正则表达式,因为它是上面所有其他正则表达式的简化和最小示例

  • ^在行首断言位置
  • ([^()\r\n])*\(((?1)|(?2))\)(?3)*将以下内容捕获到捕获组1中
    • ([^()\r\n])*多次将以下内容捕获到捕获组2中
      • [^()\r\n]匹配集合中不存在的任何字符()\r\n一次或多次
      • (?1)递归第一个子模式(1)

唐裕
2023-03-14
(?=\()(?:(?=.*?\((?!.*?\1)(.*\)(?!.*\2).*))(?=.*?\)(?!.*?\2)(.*)).)+?.*?(?=\1)[^(]*(?=\2$)

证据

瞧;就在那里。右边的括号从头到尾匹配一组完整的嵌套括号。每个匹配必须捕获并保存两个子串;这些对你没用。只需关注主要比赛的结果。

不,深度没有限制。不,这里没有隐藏的递归构造。只是简单的环顾四周,带有一点向前的参照。如果你的口味不支持转发引用(我在看你,JavaScript),那么我很抱歉。真的。我希望我能帮助你,但我不是一个神奇的工作者。

好吧,就这么定了。我们之所以能够匹配这些外部组,是因为它们不重叠。一旦我们想要的比赛开始重叠,我们必须稍微调整我们的策略。我们仍然可以检查主题是否有正确平衡的括号组。然而,我们不需要直接匹配它们,而是需要用这样一个捕获组来保存它们:

(?=\()(?=((?:(?=.*?\((?!.*?\2)(.*\)(?!.*\3).*))(?=.*?\)(?!.*?\3)(.*)).)+?.*?(?=\2)[^(]*(?=\3$))) 

与前面的表达式完全相同,除了我已经将其中的大部分包装在一个前瞻中以避免使用字符,添加了一个捕获组,并调整了反向引用html" target="_blank">索引,以便他们与新朋友玩得很好。现在,表达式在下一个括号组之前的位置匹配,并且感兴趣的子字符串保存为\1。

很高兴你问我。一般的方法非常简单:一次遍历一个字符,同时匹配下一次出现的“(”和“)”,在每种情况下捕获字符串的其余部分,以便确定在下一次迭代中恢复搜索的位置。让我把它一块一块地分解:

 类似资料:
  • 问题内容: 我正在尝试编写一个匹配嵌套括号的正则表达式,例如: 这样的字符串应该匹配,导致所有嵌套括号都被关闭,而是: 不应该或更好地至少匹配第一个“(((text)))(text)”部分。 实际上,我的正则表达式是: 但这并不能像我期望的那样正常工作。如何解决?我哪里错了?谢谢! 问题答案: 当我找到此答案时,我无法弄清楚如何修改模式以使用自己的定界符where 和。所以我的方法是使其更通用。

  • 问题内容: 我正在尝试匹配带有嵌套括号的类似数学表达式的字符串。 [‘((((1 + 0)+1)+1)’] 我希望它与所有包含的表达式匹配,例如(1 + 0),((1 + 0)+1)… 我什至不在乎它是否匹配不需要的表达式,例如(((1 + 0),我可以照顾的。 为什么它还没有这样做,我该怎么做? 问题答案: 正则表达式尝试匹配尽可能多的文本,从而消耗了所有字符串。它不会在字符串的一部分上寻找正则

  • 正如标题所说,以下是一个输入示例: 当然,匹配的字符串将通过递归进行处理。 我希望第一个递归匹配: 之后的过程不用说。。。

  • 我正在寻找一个正则表达式(**),它将匹配未知数量的嵌套函数。所以 所有的比赛都会成功。但举例来说,如果我在末尾添加一个额外的结束括号,它将不会包含在比赛中。 (**)请不要回答通过解析(和计算括号)比使用正则表达式更容易做到这一点——在挠头一会儿后,我已经知道了!

  • 我在Java的一次采访中被问到这个问题。我不能解决它,但我猜它可以解决使用正则表达式。不确定是否有一种不使用正则表达式的替代方法。有人能帮我用正则表达式吗?或者,如果不使用正则表达式就能解决这个问题。 给定一个平衡括号字符串(它只包含或,并且它已经平衡),我需要查找它内部是否包含模式(表示一个或多个平衡括号表达式)。也就是说,检查它是否在任何中包含3个或更多的。 示例: 对于,预期答案为true,

  • 问题内容: 我一直试图在Java中编写一个正则表达式以删除下面括号中的所有内容,同时保留其他所有内容。 注意,括号可以嵌套,这就是为什么我的模式失败的原因 。有人能帮我吗?下面我试过了: 但这打印: d4 Nf6 2. c4 g6 3. Nc3 Bg7 4. e4 d6 5. Nf3 OO 6. Be2 e5 7. dxe5 dxe5 8. Qxd8 Rxd8 9. Bg5 Nbd7 10. OO