Лучшее решение уже упоминалось:
somefile_(?!16\.txt$).*\.txt
Это работает и достаточно жадно, чтобы воспринимать все, что происходит на одной линии. Однако если вы знаете, что вам нужно правильное имя файла, я бы предложил также ограничить количество недопустимых символов:
somefile_(?!16)[^?%*:|"<>]*\.txt
Если вы работаете с движком регулярных выражений, который не поддерживает прогнозирование, вам придется подумать, как это сделать! 16. Вы можете разбить файлы на две группы: те, которые начинаются с 1, и за которыми не следует 6, и те, которые начинаются с чего-либо еще:
somefile_(1[^6]|[^1]).*\.txt
Если вы хотите разрешить somefile_16_stuff.txt, но НЕ somefile_16.txt, приведенных выше регулярных выражений недостаточно. Вам нужно будет установить свой лимит по-другому:
somefile_(16.|1[^6]|[^1]).*\.txt
Объедините все это, и вы получите две возможности, одна из которых блокирует один экземпляр (somefile_16.txt), а другая блокирует все семейства (somefile_16 * .txt). Я лично думаю, что вы предпочитаете первый:
somefile_((16[^?%*:|"<>]|1[^6?%*:|"<>]|[^1?%*:|"<>])[^?%*:|"<>]*|1)\.txt
somefile_((1[^6?%*:|"<>]|[^1?%*:|"<>])[^?%*:|"<>]*|1)\.txt
В версии без удаления специальных символов, чтобы было легче читать:
somefile_((16.|1[^6]|[^1).*|1)\.txt
somefile_((1[^6]|[^1]).*|1)\.txt