正则表达式负匹配问题

ned*_*edm 1 bash regex

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

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

到目前为止,这是我的尝试:

(?!msg-[0-9-]{4,16})\.html?$
Run Code Online (Sandbox Code Playgroud)

但是,这似乎不起作用。问题的一部分是先行匹配——如果整个字符串满足这些条件,我想匹配整个字符串,而不是不匹配的字符串的第一部分。任何建议,将不胜感激。

如果它对口味很重要,这将进入 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'
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 6

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

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

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

理论上可以将带有lookahaed断言的正则表达式转换为没有断言的正则表达式,但由此产生的正则表达式将是巨大的。使用两个正则表达式要简单得多:

[[ $string =~ \.html?$ && ! $string =~ msg-[-0-9]{4,16}\.html?$ ]]
Run Code Online (Sandbox Code Playgroud)

¹ 首先是基本的正则表达式 (BRE)(有几个语法变体),然后是具有更多功能的扩展正则表达式(ERE)(又是几个语法变体)。Perl 添加了更多功能,并且许多语言提供与 perl 兼容的正则表达式 (pcre)。但是 bash 坚持 ERE。