regex - 以任意顺序匹配可选捕获组

标签 regex language-agnostic

在解析用户输入的许多情况下,用户有机会向输入添加几个可选标志,这些标志应该以任何顺序接受。如何使用正则表达式对其进行解析,以便每个标志都位于其自己的捕获组中(如果存在)?

例如:

有一个必需的 token a,然后是 3 个可选 token ,可以按任意顺序出现 bc d.

一些可接受的输入是:

a
a b
a c
a b c
a c b
a b c d
a d b c
a c d b

捕获组应始终如下所示:

0 => (anything, this is ignored)
1 => a
2 => b or null
3 => c or null
4 => d or null

这个问题的几个部分已经得到解答:

  1. 使用 (...)? 表单将捕获组设置为可选
  2. 使用前瞻(?=.*b)(?=.*c)(?=.*d)允许事物按任意顺序排列

但是这些策略的组合不起作用:(a)(?=.*(b)?)(?=.*(c)?)(?=.*(d)?)

Regex101 Test

什么正则表达式允许以任何顺序找到可选标记?

(答案可以使用任何风格的正则表达式)

最佳答案

适用于多种风格的正则表达式是:

(a)(?=(?:.*(b))?)(?=(?:.*(c))?)(?=(?:.*(d))?)

这种形式是模块化的,因为添加它只需要添加另一个 (?=(?:.*(xxx))?) 到模式中。它之所以有效,是因为它强制 .* 进行回溯,但也防止 .*? 立即退出(因为可以立即匹配下一个标记)。

Regex101 Tested (适用于 PCRE、JavaScript 和 Python)

JavaScript 示例:JSFiddle

var cmd = document.getElementById("cmd"),
    pre = document.getElementById("output"),
    reg = /(a)(?=(?:.*(b))?)(?=(?:.*(c))?)(?=(?:.*(d))?)/;
cmd.onkeyup = function() {
  var m = reg.exec(cmd.value) || [],
      output = "Match\n";
  for (var i = 1; i < m.length; i++)
    output += "[" + i + "] => " + (m[i] || "null") + "\n";
  pre.innerHTML = m.length ? output : "No Match";
}
Enter command: <input id="cmd" type="text" />
<pre id="output">No Match</pre>

问题中两种策略的组合不起作用,因为 .*(x)? 形式太贪婪(它会跳过捕获组)。另一方面,.*?(x)? 太懒了(它停在第一个索引处,因为它注意到下一项是可选的)。

关于regex - 以任意顺序匹配可选捕获组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37449492/

相关文章:

java - 如何从数组列表中过滤字符串的一部分

java - 用于捕获特定数字的正则表达式

language-agnostic - 如何区分UTF-8和ASCII文件?

algorithm - 添加、获取第 k 个最大的数据结构是 O(log n) 和 O(1)

algorithm - 如何在线性时间内计算最小瓶颈生成树?

pointers - 指针是否存储为整数?

c# - 如何消除特定字符串后面的数字

python - Pandas 正则表达式返回包含 U 或 UN 和数字的任何字符串

python - 确定 sql 语句是否以单词 SELECT 开头

python - 所有最小生成树实现