正则expression式负面匹配的麻烦

我一直在试图想出一个正则expression式匹配string基于特定的文件名,我希望有一个正则expression式忍者(我会省略xkcd链接的时间)在那里谁可以帮助。

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

这是我迄今为止的尝试:

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

但是,这似乎并不奏效。 部分问题是先行匹配 – 我想匹配整个string,如果它符合这些标准,而不是不匹配的string的第一部分。 任何build议,将不胜感激。

万一它的味道很重要,这是Debian上的一个bash脚本。

编辑:

这里有一些string应该匹配正则expression式

 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' 

这里有一些不应该匹配正则expression式的string:

 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 

我认为下面的Perl正则expression式匹配你想要的:

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

然而,AFAIK没有任何地方bash支持Perl正则expression式。 =~运算符只支持扩展的正则expression式¹,它不包括(?=…)(?!…)等零宽度的前瞻断言。

理论上可以将一个正则expression式转换为一个没有的expression式,但是得到的正则expression式是巨大的。 使用两个正则expression式要简单得多:

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

¹首先有基本的正则expression式(BRE)(带有几种语法变体),然后扩展了正则expression式(ERE)和更多的function(以及几种语法变体)。 Perl增加了更多的function,许多语言提供perl兼容的正则expression式(pcre)。 但是Bash坚持ERE。

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

另外kodos一定是你的朋友; p(这是一个gui应用程序非常有用的时候乱搞正则expression式)