【问题标题】:How to match string within parentheses (nested) in Java?如何在Java中匹配括号内的字符串(嵌套)?
【发布时间】:2013-07-19 12:02:08
【问题描述】:

我想匹配括号内的字符串,例如:

(i, j, k(1))
^^^^^^^^^^^^

字符串也可以包含右括号。如何在不编写解析器的情况下将其与 Java 中的正则表达式匹配,因为这是我项目的一小部分。谢谢!

编辑:

我想搜索一个字符串块并找到类似u(i, j, k)u(i, j, k(1)) 或只是u(<anything within this paired parens>) 的内容,并将它们替换为__u%array(i, j, k)__u%array(i, j, k(1)) 用于我的Fortran 翻译应用程序。

【问题讨论】:

  • 括号是否有最大“深度”,或者你能有任何深度吗?
  • 听起来你不需要一个非常复杂的解析器...
  • 你不能用正则表达式来做到这一点,至少不能用Java,因为正则表达式不是递归的。不过,PCRE 可以做到这一点。但是您应该使用/编写解析器。例如,您可以尝试parboiled
  • @radai 我没有深度限制,但如果需要,我可以接受。
  • @LiDong 这可能是XY problem。你到底想要什么?判断字符串是否格式正确?里面的数据?什么?

标签: java regex nested


【解决方案1】:

正如我所说,与流行的看法相反(不要相信人们所说的一切)匹配嵌套括号可以使用正则表达式。

使用它的缺点是您只能达到固定的嵌套级别。对于您希望支持的每一个额外级别,您的正则表达式将会越来越大。

但不要相信我的话。让我演示给你看。正则表达式:

\([^()]*\)

Matches one level。对于up to two levels,您需要:

\(([^()]*|\([^()]*\))*\)

等等。要继续添加级别,您只需将中间(第二个)[^()]* 部分更改为([^()]*|\([^()]*\))* (check three levels here)。正如我所说,它会越来越大。

你的问题:

对于您的情况,两个级别可能就足够了。所以它的Java代码是:

String fortranCode = "code code u(i, j, k) code code code code u(i, j, k(1)) code code code u(i, j, k(m(2))) should match this last 'u', but it doesnt.";
String regex = "(\\w+)(\\(([^()]*|\\([^()]*\\))*\\))"; // (\w+)(\(([^()]*|\([^()]*\))*\))
System.out.println(fortranCode.replaceAll(regex, "__$1%array$2"));

输入:

code code u(i, j, k) code code code code u(i, j, k(1)) code code code u(i, j, k(m(2))) should match this last 'u', but it doesnt.

输出:

code code __u%array(i, j, k) code code code code __u%array(i, j, k(1)) code code code u(i, j, __k%array(m(2))) should match this last 'u', but it doesnt.

底线:

在一般情况下,解析器会做得更好——这就是人们对它如此生气的原因。但对于简单的应用程序,正则表达式就足够了。

注意: 一些正则表达式支持嵌套运算符R(Java 不支持,PHP 和 Perl 等 PCRE 引擎支持),它允许您嵌套任意数量的级别.有了它们,您可以:\(([^()]|(?R))*\).

【讨论】:

  • @acdjunior 先生,您能解释一下为什么这个正则表达式:\((?:[^()]|(?:\([^()]*\)))*\) 对任何深度都不起作用吗?
  • @AhmedAkhtar 因为它只匹配两个级别。粗略地说,它只匹配两个,因为在打开第二个括号后,它“忽略”任何其他括号打开,这意味着它找到的第一个右括号,它认为它正在关闭第二个打开的(而不是最后一个打开的)。示例:aaa 1( aaa 2( aaa 3( aaa 4) aaa 5) aaa 6) aaa..,在这种情况下,两级正则表达式将4) 解释为关闭2(,而不是您所期望的3(
  • 先生,请尝试早点回复 cmets,我发表此评论已经快一年了,我真的不记得我提出这个问题的背景。顺便说一句,谢谢。
  • @AhmedAkhtar 是的,当然,抱歉耽搁了。有时我们没有立即回答,最终完全忘记了它。无论如何,下次会尝试更快。干杯!
  • 我认为这个正则表达式不适用于像 (abc (de) (fg) hi ) 这样的嵌套模式。可以对正则表达式进行哪些修改以支持这一点?
【解决方案2】:

分开你的工作。让正则表达式为:

([a-z]+)\((.*)\)

第一组将包含标识符,第二组将包含参数。然后继续:

private static final Pattern PATTERN = Pattern.compile("([a-z]+)\\((.*)\\)");

// ...

final Matcher m = Pattern.matcher(input);

if (!m.matches())
    // No match! Deal with it.

// If match, then:

final String identifier = m.group(1);
final String params = m.group(2);

// Test if there is a paren
params.indexOf('(') != -1;

用 Fortran 中的任何标识符替换 [a-z]+

【讨论】:

    【解决方案3】:

    请检查此答案,因为它基本上可以完成您尝试做的事情(简而言之,正则表达式实际上不可能)

    Regular Expression to match outer brackets

    【讨论】:

    • 是的,正则表达式(至少在 Java 中)不是这个任务的正确工具。我想我应该改变我的计划,只匹配 u( 并将其替换为 __u%array(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    相关资源
    最近更新 更多