我想找到两个
RegExp
:
RegExp
是否包含捕获组,如 /ab(c)d/
/ab(?<name>c)d/
source
属性。
这是我对 1 的最佳尝试:
/(?<!\\)\((?!\?:)/
。
这个想法是寻找一个前面没有 \
且后面没有 ?:
的左括号(这将使其成为非捕获组)。但这有误报(例如/c[z(a]d/
)和漏报/a\\(b)/
。
我对 2. 的尝试遵循相同的逻辑,因此具有相同的缺陷:
/(?<!\\)\(\?<(?![=!])/
知道如何正确执行此操作吗?谢谢。
您可以使用正则表达式,除了发现捕获组之外,还捕获转义对 (
\\.
) 和字符类 \[(?:\\.|.)*?\]
(也知道转义字符),以避免误报/漏报。然后循环查看匹配项以发现好的匹配项。
以下代码片段返回匿名捕获组的数量以及命名捕获组的名称:
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));
查看 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 解决方案。不过它确实有效。