【问题标题】:Match a given regex except if a given word exist (lookahead or lookbehind)匹配给定的正则表达式,除非存在给定的单词(lookahead or lookbehind)
【发布时间】:2016-08-25 05:01:34
【问题描述】:

我正在使用 javascript 正则表达式来解析一系列 URL。我需要匹配 URL 中的数字(实际上更复杂,但我正在简化),但只想匹配给定单词不在 URL 中的数字。

也就是说,我想排除其中包含“changelogs”一词的行,因此会捕获“1047”、“1048”、“1245 ' 和 '1049' 来自以下列表;

http://www.opera.com/docs/changelogs/unified/1215/
http://www.whatever.com/docs/changelogs/anythingelse/anything/1215/
http://www.blabblah/security/advisory/1047
http://booger/security/advisory/1048/
ftp://msn.global.whatever/somethingelse/1245
whatever/it/doesnt/matter/could/be/anything/i/still/want/this/number/1049/

我知道我需要某种环顾四周、前瞻后瞻的方式,但我正在三振出局。这是我尝试过的最后一种模式;

(?!changelogs)(\d+)

Here is the regex101 sandbox I'm using.

此外,唯一匹配的是实际数字也很重要。我不希望其他任何东西匹配


这是我的 .NET 代码的样子(注意“BulletinOrAdvisoryPattern”是有问题的正则表达式)...

Regex bulletinPattern = new Regex(@matchingDomain.Vendor.BulletinOrAdvisoryPattern, RegexOptions.IgnoreCase );
Match bulletinMatch = bulletinPattern.Match(referenceTitle);

                    if (bulletinMatch.Success)
                    {
                        //Found the bulletin ID in the NVD Reference Title 
                        return bulletinMatch.Value;
                    }

【问题讨论】:

  • 不知道怎么访问Match.Groups[1].Value?此外,您不需要正则表达式。为什么要使用正则表达式?此外,如果您需要.NET regex,为什么要使用仅支持 Python/PCRE/JS 的 regex101?
  • JavaScript 没有后视功能。您必须使用^(?!.*\/changelogs(?:\/|$)).*\/(\d+) 之类的消费模式。要求 此外,唯一匹配的是实际数字也很重要。我不希望有任何其他匹配。 使这个问题不清楚且无法回答。
  • @WiktorStribiżew 请查看我的编辑以了解我的意思。目前,我所有用于模式匹配的正则表达式都明确匹配我需要的内容(例如,我可能有一个带有单词“duck”的正则表达式,并且“return bulletinmatch.value”将返回完全匹配的鸭子,或者我可能有一个正则表达式匹配数字,并且“return bulletinmatch.value”行将仅返回该数字。我宁愿不必指定一个组,因为该组对于我匹配的每个域都会有所不同。这有意义吗?
  • 这是有道理的,这意味着您需要更改该方法以返回特定组。由于匹配值始终为 Group 0,因此您可以指定 0 参数来获取 match.value,并指定 1 获取第一个捕获的值,2 获取第二个值,依此类推。在 JS 中你不能这样做。

标签: javascript regex lookahead lookbehind


【解决方案1】:

你需要的“丑陋”的正则表达式是

(?<=http://www\.opera\.com\b(?!.*/changelogs(?:/|$))\S*)\d+

.NET regex demo

然而,你所需要的只是

var result = input.Contains("/changelogs/") ? "" : input.Trim('/').Split('/').LastOrDefault();

IDEONE C# demo

var lst = new List<string>() {"http://w...content-available-to-author-only...a.com/docs/changelogs/unified/1215/",
    "http://w...content-available-to-author-only...a.com/docs/changelogs/anythingelse/anything/1215/",
    "http://w...content-available-to-author-only...a.com/security/advisory/1047",
    "http://w...content-available-to-author-only...a.com/security/advisory/1048/",
    "http://w...content-available-to-author-only...a.com/doesnt/matter/could/be/anything/1049/"};
lst.ForEach(m => Console.WriteLine(
        m.Contains("/changelogs/") ? "" : m.Trim('/').Split('/').LastOrDefault()
    ));

更新

您将语言从 C# 切换到 JavaScript,这极大地改变了这种情况,因为 JS 正则表达式引擎不支持后视。

因此,您必须解决它,并且有一些方法可以模仿后视,或者只是使用捕获机制。

如果你可以使用捕获,试试

/^(?!.*\/changelogs(?:\/|$)).*\/(\d+)/

regex demo

var re = /^(?!.*\/changelogs(?:\/|$)).*\/(\d+)/gmi; 
var str = 'http://www.opera.com/docs/changelogs/unified/1215/\nhttp://www.whatever.com/docs/changelogs/anythingelse/anything/1215/\nhttp://www.blabblah/security/advisory/1047\nhttp://booger/security/advisory/1048/\nftp://msn.global.whatever/somethingelse/1245\nwhatever/it/doesnt/matter/could/be/anything/i/still/want/this/number/1049/';
var res = [];
 
while ((m = re.exec(str)) !== null) {
  res.push(m[1]);
}
document.body.innerHTML = JSON.stringify(res, 0, 4);

或者,使用可选组(如果要替换):

var re = /(\/changelogs\/.*)?\/(\d+)/gi; 
var str = 'http://www.opera.com/docs/changelogs/unified/1215/\nhttp://www.whatever.com/docs/changelogs/anythingelse/anything/1215/\nhttp://www.blabblah/security/advisory/1047\nhttp://booger/security/advisory/1048/\nftp://msn.global.whatever/somethingelse/1245\nwhatever/it/doesnt/matter/could/be/anything/i/still/want/this/number/1049/';
var result = str.replace(re, function (m, g1, g2){
  return g1 ? m : "NEW_VAL";
});
document.body.innerHTML = result;

【讨论】:

    【解决方案2】:

    类似下面的东西应该可以做到。如果您不仅对歌剧感兴趣,则可以通过将 opera 替换为 .+ 来将其调整为更通用。此外,您可以将 com 和 net 之类的东西匹配为 (com|net|org|gov) 之类的东西来代替 com:

    http:\/\/www\.opera\.com(?!.*changelogs)(\/[^\/]+)*\/(\d+)\/{0,1}
    

    Here is your regex 101 updated to reflect this

    【讨论】:

    • 感谢您的回复。确实,我不关心域部分(上半部分)。我尝试用 .+ 替换前半部分,但随后它在每一行上都匹配。相反,我将其更改为匹配反斜杠。 regex101.com/r/tC7tA7/6 无论如何要让它不在乎更新日志之前的内容?
    【解决方案3】:

    此模式排除其中包含“更改日志”的行,并查找最后出现的由斜线封装的数字。

    (?:\/)(?!.*changelogs)(?:\/[^\/]+)*\/(\d+)\/{0,1}
    

    这里是updated regex 101

    【讨论】:

    • 谢谢,但只有数字/号码应该匹配。这是每行返回两个匹配项
    猜你喜欢
    • 2021-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    相关资源
    最近更新 更多