长命名捕获组正则表达式模式的问题

Problem with long named capturing groups regex patterns

我已经创建并初步验证了以下正则表达式。它旨在成为分词器的一部分,在将某些模式传递给解析器之前对其进行识别和分组。

(?<FUNCTION> (?!CUP\(\d+\)|CDN\(\d+\))[A-Z]+\(\d*\)|[A-Z]+\(\d+,\d+\))
| (?<NUMBER>\d+|\d*\.\d+)
| (?<RELATION>==|<=|>=|!=|<|>|CUP\(\d+\)|CDN\(\d+\))
| (?<EOL>;)
| (?<OPENPAR>\()
| (?<CLOSEPAR>\))
| (?<OPERATION>\*|\+|-|\/])
| (?<SPACE>\s+)
| (?<ERROR>.)

通过以上内容,使用正则表达式引擎属性以及降低子模式的复杂性,我能够正确地捕获所有组。下面的示例文本按预期匹配,捕获命名捕获组中的正确部分(在 regex101 上:https://regex101.com/r/nvRyjt/2)。到目前为止一切顺利。

TICK()<=.(2*STDEVEMA(14))+EMA(14);
TREND(14,2)==UP(2);
TICK()>EMA(14);
TREND(14)==UP(1);
EMA(14)CUP(2)EMA(28);
EMA(14)CDN(2)EMA(28)
2*3==6;
ssst2222  \\///???
sfgjsf

当我尝试在 java.util.regex 中使用此表达式时出现问题。对于较小的组,模式只捕获很少的出现,并且输入文本的剩余可识别部分被跳过或显示为 'nulls'。我尝试了很多组合,包括将模式限制为两个或三个组,但对于导致意外行为的原因没有明确的结论。通过搜索到目前为止发布的问题,我清楚地注意到 regex101(和一般的 PCRE)不是验证稍后在 java :-) 中使用的正则表达式的好工具。发帖时我想问以下问题:

  1. 你们中有人知道有关 Pattern 和 Matcher 类 工作原理(尤其是正则表达式引擎)的任何深入描述吗?
  2. 您是否遇到过类似的复杂正则表达式模式的问题(也许 java.util 有某些不那么明显的限制)?

还有一个更具体的事情,具有负面的前瞻性。像这样构造:

(?<FUNCTION> (?!CUP\(\d+\)|CDN\(\d+\))[A-Z]+\(\d*\)|[A-Z]+\(\d+,\d+\))

仅跳过第一个字符 'C' 表示关键字的剩余部分(CUP 或 CDN)有效(在本例中为 UP 或 DN)。对此有什么想法吗? 提前致谢!

我不确定我是否能回答你的问题,但你可以试试下面的方法。

使用 regex101 站点上的代码生成器工具(在工具下方的左侧)并使用 java 作为您的语言。

从生成的正则表达式字符串中删除 \n。不删除它可能会导致您的问题?!​​

package com.company;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {

        final String regex = "(?<FUNCTION> (?!CUP\(\d+\)|CDN\(\d+\))[A-Z]+\(\d*\)|[A-Z]+\(\d+,\d+\))" +
                " | (?<NUMBER>\d+|\d*\.\d+)" +
                " | (?<RELATION>==|<=|>=|!=|<|>|CUP\(\d+\)|CDN\(\d+\))" +
                " | (?<EOL>;)" +
                " | (?<OPENPAR>\()" +
                " | (?<CLOSEPAR>\))" +
                " | (?<OPERATION>\*|\+|-|\/])" +
                " | (?<SPACE>\s+)" +
                " | (?<ERROR>.)";
        final String string = "TICK()<=.(2*STDEVEMA(14))+EMA(14);\n"
                + "TREND(14,2)==UP(2);\n"
                + "TICK()>EMA(14);\n"
                + "TREND(14)==UP(1);\n"
                + "EMA(14)CUP(2)EMA(28);\n"
                + "EMA(14)CDN(2)EMA(28)\n"
                + "2*3==6;\n"
                + "ssst2222  \\\\///???\n"
                + "sfgjsf\n";

        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE | Pattern.COMMENTS);
        final Matcher matcher = pattern.matcher(string);

        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            for (int i = 1; i <= matcher.groupCount(); i++) {
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
        }
    }
}

注意

我得到了 67 个匹配项,regex101 得到了 89 个匹配项。

这是因为 SPACE 在 regex101 中的 ERROR 之前匹配。在 Java 中不是。可能是 regex101 支持的扩展模式,在 Java.

中似乎不可用

示例:

final String string = "TICK()<=."

在Java中给出:

Full match: TICK()
Full match: <=
Full match: .

在 regex101 中给出:

Match 1  Full match 0-6 TICK()
Match 2  Full match 6-8 <= 
Match 3  Full match 8-8  
Match 4  Full match 8-9 .