在解析用户输入时有很多情况,用户有机会向输入添加几个可选标志,这些标志应该以任何顺序被接受。如何使用正则表达式对其进行解析,以便每个标志位于其自己的捕获组中(如果存在)?
例如:
有一个必需的令牌a
,然后有3个可选令牌,可以按任意顺序排列b
,c
和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
这个问题有几个部分已经得到解答:
(...)?
表单使捕获组可选(?=.*b)(?=.*c)(?=.*d)
允许事物处于任何顺序但这些策略的组合不起作用:(a)(?=.*(b)?)(?=.*(c)?)(?=.*(d)?)
什么正则表达式允许以任何顺序找到可选令牌?
(答案可以使用任何风格的正则表达式)
答案 0 :(得分:1)
适用于多种口味的正则表达式是:
(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)?
太懒了(它在第一个索引处停止,因为它注意到下一个项是可选的)。