如何测试正则表达式的定义中是否包含捕获组?

问题描述 投票:0回答:2

我想找到两个

RegExp
:

  1. 一个用于测试另一个
    RegExp
    是否包含捕获组,如
    /ab(c)d/
  2. 中所示
  3. 与 1. 相同,但仅检测命名的捕获组,例如
    /ab(?<name>c)d/

这些“元”正则表达式将检查正则表达式的

source
属性

这是我对 1 的最佳尝试:

/(?<!\\)\((?!\?:)/
。 这个想法是寻找一个前面没有
\
且后面没有
?:
的左括号(这将使其成为非捕获组)。但这有误报(例如
/c[z(a]d/
)和漏报
/a\\(b)/

我对 2. 的尝试遵循相同的逻辑,因此具有相同的缺陷:

/(?<!\\)\(\?<(?![=!])/

知道如何正确执行此操作吗?谢谢。

javascript regex
2个回答
3
投票

您可以使用正则表达式,除了发现捕获组之外,还捕获转义对 (

\\.
) 和字符类
\[(?:\\.|.)*?\]
(也知道转义字符),以避免误报/漏报。然后循环查看匹配项以发现好的匹配项。

以下代码片段返回匿名捕获组的数量以及命名捕获组的名称:

const reParser = /\\.|\[(?:\\.|.)*?\]|(\()(?!\?)|\(\?<([^=!][^>]*)/g;
function captureGroups(regex) {
    const names = [];
    let numAnonymous = 0;
    for (const [match, anon, name] of regex.source.matchAll(reParser)) {
        if (name) names.push(name);
        else if (anon) numAnonymous++;
    }
    return { numAnonymous, names };
}

// Example run
console.log(captureGroups(/test[12\](3]*(?<xy>((\.))?)/g));

如果您只需要知道是否存在捕获组,那么您可以首先从正则表达式中删除这些转义对和字符类,并用单个字符替换它们。然后剩下的就是识别捕获组模式:

function hasCaptureGroups(regex) {
    const simpler = regex.source.replace(/\\.|\[(?:\\.|.)*?\]/g, "x");
    return {
        hasAnonymous: /\([^?]/.test(simpler),
        hasNamed: /\(\?</.test(simpler)
    };
}

// Example run
console.log(hasCaptureGroups(/test[12\](3]*(?<xy>((\.))?)/g));

要仅使用正则表达式而不进行替换来完成此操作,您需要专注于匹配not具有捕获组的输入,然后否定它——这可以通过对第一个位置,扫描完整的输入:

const reAnonymousGroup = /^(?!(\\.|\[(?:\\.|.)*?\]|[^(]|\(\?)*$)/;
const reNamedGroup     = /^(?!(\\.|\[(?:\\.|.)*?\]|[^(]|\([^?]|\(\?[^<])*$)/;

// Example run
const regex = /test[12\](3]*(?<xy>((\.))?)/g;
console.log("has anonymous group:", reAnonymousGroup.test(regex.source));
console.log("has named group:", reNamedGroup.test(regex.source));


0
投票

查看 RegExp 是否具有捕获组的一种方法是进行匹配并查看其

.length
。如果是
1
,则整场比赛除了零组之外没有任何捕获组。

创建一个 RegExp 一定会匹配的输入并不是一件容易的事。在一般情况下,这相当困难,并且需要对正则表达式进行更多的解析,而不是直接从源中计算捕获组所需的数量。

相反,您可以创建一个具有相同数量捕获组的正则表达式,并且很容易匹配,然后只需匹配它并查看匹配的

length

function reCaptureGroupCount(re) {
  var re1 = RegExp("|" + re.source);
  var match = re1.exec("");
  return match.length; // -1 if you don't want to count group 0.
}

这不是问题的 RegExp 解决方案。不过它确实有效。

© www.soinside.com 2019 - 2024. All rights reserved.