以任何顺序匹配可选捕获组
在解析用户输入时存在许多情况,其中用户有机会向输入添加若干可选标志,这些标志应该以任何顺序被接受。 如何使用正则表达式对其进行解析,以便每个标志位于其自己的捕获组中(如果存在)?
例如:
有一个必需的令牌a
,然后是3个可选的令牌,它们可以按任何顺序排列b
, c
和d
。
一些可接受的输入将是:
a ab ac abc acb abcd adbc acdb
捕获组应始终如下所示:
0 => (anything, this is ignored) 1 => a 2 => b or null 3 => c or null 4 => d or null
这个问题有几个部分已经得到解答:
- 使用
(...)?
表单以使捕获组可选 - 使用先行
(?=.*b)(?=.*c)(?=.*d)
允许事物处于任何顺序
但这些策略的组合不起作用: (a)(?=.*(b)?)(?=.*(c)?)(?=.*(d)?)
Regex101测试
正则表达式允许以任何顺序找到可选令牌?
(答案可以使用任何风格的正则表达式)
适用于多种口味的正则表达式是:
(a)(?=(?:.*(b))?)(?=(?:.*(c))?)(?=(?:.*(d))?)
这种forms是模块化的,因为添加它只需要在模式上添加另一个(?=(?:.*(xxx))?)
。 它起作用是因为它迫使.*
进行回溯,但也保持一个.*?
立即退出(因为下一个令牌可以立即匹配)。
Regex101经过测试 (适用于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: No Match