Я был разочарован, пытаясь придумать регулярное выражение для сопоставления строк на основе определенных имен файлов, и я надеюсь, что есть ниндзя регулярных выражений (я опущу обязательную ссылку xkcd ради времени), который может помочь.

Мне нужно сопоставить любую строку, оканчивающуюся на «.htm» или «.html», которая НЕ (отрицательное сопоставление), которой непосредственно предшествует «msg-», за которым следуют 4–16 цифр чисел или дефисов. Начало строки может быть любой длины или любого содержания.

Вот моя попытка:

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

Однако, похоже, это не работает. Частично проблема заключается в сопоставлении с опережением - я хочу сопоставить всю строку, если она соответствует этим критериям, а не первую часть строки, которая не соответствует. Мы ценим любые предложения.

В случае, если это имеет значение для вкусов, это входит в сценарий bash в Debian.

РЕДАКТИРОВАТЬ:

Вот несколько строк, которые должны соответствовать регулярному выражению

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
answer

Я думаю, что следующее регулярное выражение Perl соответствует тому, что вы хотите:

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

Однако, AFAIK, нет места, где bash поддерживает регулярные выражения Perl. =~Оператор поддерживает только расширенный regexps¹, которые не включают в себя нулевой ширины LookAhead утверждения , такие как (?=…)и (?!…).

Теоретически возможно преобразовать регулярное выражение с утверждениями, содержащими поиск, в одно без, но в результате регулярное выражение будет огромным. Гораздо проще использовать два регулярных выражения:

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

¹ Сначала были базовые регулярные выражения (BRE) (с несколькими вариантами синтаксиса), затем появились расширенные регулярные выражения (ERE) с дополнительными функциями (и снова несколько вариантов синтаксиса). Perl добавил еще больше возможностей, и многие языки предоставляют Perl-совместимые регулярные выражения (pcre). Но bash придерживается ERE.

попробуйте с ^(?!\w+msg-\d+.[html|htm]+).*$

Также kodos должен быть вашим другом; p (это приложение с графическим интерфейсом очень полезно, когда вы возитесь с regexpr)