<h1((?!</h1).)*</h1>((?!<p).)*<h2
должно работать.
Он соответствует ровно одному тегу h1
, затем любому количеству символов до следующего тега h2
, но только если по пути не найдено тега p
.
Поскольку в этом сценарии маловероятно, что появятся вложенные теги, это должно быть достаточно надежно, даже с регулярным выражением.
Вам нужно будет активировать опцию вашего инструмента / языка, чтобы точка соответствовала символам новой строки. Для этого может быть достаточно добавить к вашему регулярному выражению (?s)
.