正则表达式负匹配问题

正则表达式负匹配问题

我一直很沮丧地尝试想出一个正则表达式来匹配基于特定文件名的字符串,并希望有一个正则表达式忍者(为了节省时间,我将省略强制性的 xkcd 链接)可以提供帮助。

我需要匹配以“.htm”或“.html”结尾的任何字符串,该字符串不以“msg-”开头(负匹配),后面紧跟着 4-16 位数字或连字符。字符串的开头可以是任意长度或内容。

这是我迄今为止的尝试:

(?!msg-[0-9-]{4,16})\.html?$

但是,这似乎不起作用。问题的一部分是前瞻匹配——如果符合这些条件,我希望匹配整个字符串,而不是不匹配的字符串的第一部分。任何建议都将不胜感激。

如果它对风格有影响,那么这将进入 Debian 上的 bash 脚本。

编辑:

以下是一些应与正则表达式匹配的字符串

the-quick-brown-fox-jumped-over-the-lazy-dog.html  # ends with .html but no digits/hyphens just prior
wdihwi94uq239ujdf23yefh02msg-2-8.htm   # digit/hyphen count between 'msg-' and '.html' is below 4
ohdf23890yo4c89uwmsg-999-24j345.html   # non-number/hyphen in chars between 'msg-' and '.html'

以下是一些不应与正则表达式匹配的字符串:

kh3j42he2-dwfascn233=feufefask0msg-34535-355  # does not end with '.htm'/'.html'
395-u78{efihighqwioh9msg-8455-212.html  # ends with 'msg-' then 4-16 of [0-9-] then '.html'
dfhjwih9asnm)qpzmx.wod923klsj39msg-00-0000.htm

答案1

我认为以下 Perl 正则表达式符合您的要求:

(?!.*msg-[-0-9]{4,16}\.html?$).*\.html?$

但是据我所知,bash 没有任何地方支持 Perl 正则表达式。该=~运算符仅支持扩展正则表达式¹,其中不包括零宽度前瞻断言,例如(?=…)(?!…)

理论上可以将带有 lookahaed 断言的正则表达式转换为不带有 lookahaed 断言的正则表达式,但生成的正则表达式会非常大。使用两个正则表达式要简单得多:

[[ $string =~ \.html?$ && ! $string =~ msg-[-0-9]{4,16}\.html?$ ]]

¹ 首先是基本的正则表达式(BRE)(有几种语法变体),然后出现了延长regexps (ERE) 具有更多功能(同样还有几种语法变体)。Perl 添加了更多功能,许多语言都提供与 perl 兼容的 regexps (pcre)。但 bash 坚持使用 ERE。

答案2

尝试^(?!\w+msg-\d+.[html|htm]+).*$

另外,kodos 一定是你的朋友 ;p(这是一个 GUI 应用程序,在使用正则表达式时非常有用)

相关内容