Java RegEx 循环引用模式

标签 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");

你已经看到我的问题了:我在 factor 的定义中引用了术语,而没有先定义它。不幸的是,我无法以任何方式切换它。所以我的问题是:

是否有可能以这种方式引用模式?或者任何其他引用模式并在以后定义它的方法?

最佳答案

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

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

如果您想解决手头的任务,您将不得不手动编写解析。如果你想学习正则表达式,你要么用另一种语言学习,要么寻找不同的任务。但是,这里有一个 great source to improve your regex skills .

为了好玩(并向您展示为什么正则表达式不是正确的工具,即使引擎支持必要的功能),这里是对应于上述 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
$

关于Java RegEx 循环引用模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13792289/

相关文章:

java - 使用正则表达式格式化字符串日期

java - 使用更窄的参数化覆盖泛型方法

java - 2人项目——java+数据库程序员

java - 如何将字符串转换为数组的名称?

Java替换字符串html img标签

Java 刽子手。如何创建多个按钮和 Action 监听器?

python - 拆分名称列表,其中两个名字可能有共同的姓氏

java - 使用可选的逗号和点匹配数字

java - 正则表达式在 Java 中失败

python - 正则表达式匹配非字母字符(复合词的连字符除外)