如何匹配以任何顺序出现并且最多出现一次的一组字符?

时间:2016-03-09 04:22:16

标签: ruby regex

我正在尝试为一个东西编写一个非常非常基本的解析器,作为其中的一部分,我决定使用正则表达式来查找正则表达式。

这是正则表达式的样子:

r/pattern/flags

除了/可以是/|:!`.中的任何一个。例如,您可以匹配没有大量\/ s的网址。现在,这就是我到目前为止:

r([\/|:!`.])(.*?)(?<![^\\]\\)\1x?m?i?g?a?s?

但是,这有一个问题:它与r/abcde/ai不匹配。鉴于应该能够以任何顺序指定标志,这将失败。我也试过这个:

r([\/|:!`.])(.*?)(?<![^\\]\\)\1([xmigas]+)

但这有一个问题,它允许r|abc|aaaasxmaaaiisggss,它不应该。如果我将其限制为[xmigas]{,6},我仍然可以写|iiiii

现在,我意识到我可以做很长很复杂的事情,但这不可能扩展,所以我宁愿避免它。有没有办法匹配一组最多可以出现一次,任何顺序,没有任何复杂的字符?

在这种特殊情况下,我使用Ruby,如果有必要,我可以添加宝石。我也许能够切换语言,虽然它需要做很多工作而且我更不愿意。

这是一个个人项目,旨在为了好玩。请忽略使用正则表达式搜索正则表达式的想法有多糟糕。

2 个答案:

答案 0 :(得分:2)

Negative lookahead应该做你想做的事。为简单起见,我将忽略除标志匹配部分之外的所有内容。

请考虑以下事项:

(?:([xmigas])(?!.*\1.*))*

我们寻找有效的旗号,但我们断言此旗帜字母后面的内容不再包含相同的旗帜字母。然后我们重复整个事情0次或更多次(让前瞻隐含地防止存在任何额外的标志)。

答案 1 :(得分:0)

这匹配x,m,i,g,a,s的所有组合,没有重复:

^(?:([xmigas])(?!.*\1))*$

特别是在你的情况下,表达式将是

/^r([\/|:!`.])(.*?)\1(?:([xmigas])(?!.*\3))*$/

在行动here

中查看

另外,请参阅@ Chris的答案了解详情