Java RegEx循环引用模式



我想学习如何在Java中使用正则表达式,并发现了以下任务:根据以下BNF形式的标准,编写一个类来检查给定的输入字符串是否是有效的算术项:

term = [Vz]summand|[Vz]summand addOp term
summand = factor | factor mulOp summand
factor = number | '('term')'
number = digit | digit number
digit = '0'|'1'|...|'9'
vz = '+'|'-'
addOp = '+'|'-'
mulOp = '*'|'/'

使用这些规则,我编写了一些模式,类似于不同的类型:

static Pattern vz = Pattern.compile("[+-]");
static Pattern addOp = Pattern.compile("[+-]");
static Pattern multOp = Pattern.compile("[*/]");
static Pattern digit= Pattern.compile("[0-9]");
static Pattern number = Pattern.compile(digit.pattern()+"+");
static Pattern factor = Pattern.compile(number.pattern()+"|("+term.pattern()+")");
static Pattern summand = Pattern.compile(factor.pattern()+"|"+factor.pattern()+ multOp.pattern()+"n");
static Pattern term = Pattern.compile(vz.pattern()+"?"+summand.pattern()+"|"
+vz.pattern()+"?"+summand.pattern()+addOp.pattern()+"n");

你们已经看到了我的问题:我在因子的定义中引用了这个术语,但没有先定义它。不幸的是,我无法以任何方式改变它。所以我的问题是:

有没有可能以这种方式引用一个模式?或者其他引用模式并在以后定义它的方法?

问题是,BNF定义了一个上下文无关语法(它描述的语言比正则表达式描述的语言更复杂)。您必须想出一种不同的方法,而不是直接将BNF规则用作正则表达式模式。

特别是,括号的正确嵌套是不规则的。一些正则表达式引擎支持(非正则)功能,允许匹配这些功能,但正则表达式往往变得非常长且无法维护。我现在不确定Java是否有这些特性(例如PCRE和.NET有)。

如果你想解决手头的任务,你必须手动编写一个解析。如果你想学习正则表达式,你要么用另一种语言学习,要么找一个不同的任务。然而,这里有一个很好的来源来提高您的正则表达式技能。

为了好玩(并向您展示为什么正则表达式不是正确的工具,即使引擎支持必要的功能),以下是与上述BNF相对应的正则表达式(除了Vz规则,由于一些奇怪的原因,我无法使其工作):

^(((d+|[(](?1)[)])|(?3)[*/](?2))|(?2)[+-](?1))$

(?n)递归地尝试匹配nth子模式(通过从左到右打开括号来计数)。

它在PHP中不起作用,但我相信他们的PCRE实现在使用递归时存在一些回溯问题。在线PCRE测试人员似乎正确地处理了一些示例输入。这里它处于自由间隔模式(x),带有一些注释:

^
(                # term (?1)
(              # summand (?2)
(            # factor (?3)
d+        # number
|
[(](?1)[)] # (term)
)            # end of factor
|
(?3)[*/](?2) # factor mulOp summand
)              # end of summand
|
(?2)[+-](?1)   # summand addOp term
)                # end of term
$

最新更新