如何强制正则表达式捕获最大的匹配项?

How to Force Regex to Capture Largest Match?

我正在尝试防止对网站的恶意注入。我这样做的方法是创建一个函数,该函数 "trims" URL 的任何额外部分都会使其成为非法。

为了使 URL 合法,它必须遵循以下格式:

(anything)(one of several specificied path predecessors)(specific page)

例如,假设您的路径前辈是...

["services", "services/city", "specials", "specials/limited/"]

一些示例输入和结果:

www.fake.com/services/home -> (legal, no trim) -> www.fake.com/services/home

www.fake.com/services/city/nyc -> (legal, no trim) -> www.fake.com/services/city/nyc

www.fake.com/services/city/nyc/fakeinjection.txt -> (illegal) -> www.fake.com/services/city/nyc

www.fake.com/specials/limited/california/fake/fake/fake.bak -> (illegal) -> www.fake.com/specials/limited/california

所以我写了下面的正则表达式只匹配输入的合法部分URL:

/.*(services|services\/city|specials|specials\/limited)\/[^\/]*/gi

问题在于它并不总是捕获最大可能的匹配项,因此无意中trim忽略了太多。例如:

www.fake.com/services/city/nyc -> (应该合法,不应该trim) -> www.fake.com/services/city/

我想我明白为什么会这样。我相信它正在捕获它看到的第一件事并与之匹配。但是我需要强制它尽可能地取最大的一个,必要时只 trimming。我认为 "greedy" 标志可以帮助做到这一点,但事实并非如此。

任何人都可以提供一些解决方案的指导吗?将不胜感激。

(PS。以防万一,我使用的语言是 javascript)

如果你有一个未锚定的交替组,你应该把最长的交替组放在第一位。在任何 NFA 正则表达式中,第一个匹配的分支停止处理交替组并继续处理后续模式。

所以,您可以使用

/.*(services\/city|specials\/limited|services|specials)\/[^\/]*/
    ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^

regex demo

如果您使用可选组手动创建模式以减少回溯,您可以进一步增强此列表:

/.*(services(?:\/city)?|specials(?:\/limited))\/[^\/]*/

甚至

/.*(s(?:ervices(?:\/city)?|pecials(?:\/limited)))\/[^\/]*/