Регулярное выражение соответствует нескольким строкам до и после слова, разделенным начальным и конечным словами

Я хочу найти {{ upc }} и начать захват не с <div непосредственно перед матчем, а со 2-го <div перед матчем, т.е. <div class="form-group">, и захватывать не до первого </div> после матча, а со 2-го, т.е. до закрытия </div> начало следующего <div class="form-group"> (в зависимости от того, как на это посмотреть)

Вот пример шаблона HTML/Twig, который я хочу найти и заменить.

<div class="form-group">
    <label class="col-sm-2 control-label" for="input-sku"><span data-toggle="tooltip" title="{{ help_sku }}">{{ entry_sku }}</span></label>
    <div class="col-sm-10">
        <input type="text" name="sku" value="{{ sku }}" placeholder="{{ entry_sku }}" id="input-sku" class="form-control"/>
    </div>
</div>
<div class="form-group">
     <label class="col-sm-2 control-label" for="input-upc"><span data-toggle="tooltip" title="{{ help_upc }}">{{ entry_upc }}</span></label>
     <div class="col-sm-10">
         <input type="text" name="upc" value="{{ upc }}" placeholder="{{ entry_upc }}" id="input-upc" class="form-control"/>
     </div>
</div>
<div class="form-group">
     <label class="col-sm-2 control-label" for="input-ean"><span data-toggle="tooltip" title="{{ help_ean }}">{{ entry_ean }}</span></label>
     <div class="col-sm-10">
         <input type="text" name="ean" value="{{ ean }}" placeholder="{{ entry_ean }}" id="input-ean" class="form-control"/>
     </div>
</div>

Ожидаемое соответствие регулярному выражению выглядит следующим образом:

<div class="form-group">
     <label class="col-sm-2 control-label" for="input-upc"><span data-toggle="tooltip" title="{{ help_upc }}">{{ entry_upc }}</span></label>
     <div class="col-sm-10">
         <input type="text" name="upc" value="{{ upc }}" placeholder="{{ entry_upc }}" id="input-upc" class="form-control"/>
     </div>
</div>

Вся помощь приветствуется. Спасибо.


person Trent Renshaw    schedule 20.04.2020    source источник
comment
Покажите нам, что вы уже пробовали.   -  person samthegolden    schedule 20.04.2020
comment
@samthegolden Я начинаю с /^.*(?={{ sku }}).*/gm в регулярном выражении101, хотя это, вероятно, слишком расплывчато для отправной точки. Я буду продолжать возиться, и если я решу, отправьте это здесь, но я подозреваю, что мастер регулярных выражений опередит меня!   -  person Trent Renshaw    schedule 20.04.2020
comment
отредактируйте пост своим кодом   -  person samthegolden    schedule 20.04.2020
comment
Проверьте мой отредактированный ответ.   -  person samthegolden    schedule 20.04.2020


Ответы (2)


Одна вещь, которую вы можете попробовать, — это использовать отрицательный просмотр вперед, чтобы отфильтровать вещи, которые вы не хотите включать в свой матч. Например, сопоставление <div, за которым следует что-либо, а затем еще одно <div, может соответствовать таким вещам, как <div></div><div>.

Вместо этого вы можете сказать, что нужно сопоставить <div, за которым следует что угодно, если только это не </div>, а затем еще <div.

<div    (?:(?!</div>).)*    <div

Затем вы можете вставить тот же подшаблон в любом месте вашего выражения, где вы обычно пишете .*. В этом конкретном случае вы можете повторить это, чтобы убедиться, что вы не нажимаете закрывающий div перед UPC, и затем продолжить с части {{ UPC }}.

<div(?:(?!</div>).)*<div    (?:(?!</div>).)*    {{ upc }}    .*?</div>\s*</div>

Вот демо

person Quixrick    schedule 27.04.2020
comment
Идеально и высоко ценится. Благодарю вас! - person Trent Renshaw; 28.04.2020

Вам нужно проанализировать нужные вам div, а затем поглотить все, что внутри них, и исключить все остальное.

[\w\W] означает совпадение слов и не слов. Например, он соответствует символам новой строки, а * — нет.

[\w\W]*(<div[\w\W]*?<div[\w\W]*?{{ sku }}[\w\W]*?<\/div>[\w\W]*?<\/div>)[\w\W]*

person samthegolden    schedule 20.04.2020
comment
спасибо, но это слишком жадно со слишком большим количеством шагов. Код HTML/Twig — это лишь небольшая часть всего документа. К сожалению, это регулярное выражение соответствует всем до и после {{ sku }}. В конце концов я решил начать захват слева направо, начиная с открытия <div>, соответствующего {{ sku }} (без захвата) в середине, до следующего запуска <div> следующим образом: (<div class="form-group">.*(?:{{ sku }}).*)(?:<div class="form-group">) - person Trent Renshaw; 20.04.2020
comment
Вы сказали, что хотите захватить 2 div перед выбранным словом... - person samthegolden; 20.04.2020
comment
Кстати, это не соответствует вашему примеру: regex101.com/r/QkK8LY/1 - person samthegolden; 20.04.2020
comment
Вы используете модификатор /gm вместо /s для точки, чтобы соответствовать символам новой строки. Пример: regex101.com/r/yFPT9o/1 .. Регулярное выражение по-прежнему не является решением, поскольку оно начнет соответствие с первого <div class="form-group"> до {{ sku }}. Я думаю, что это будет задача смотреть вперед и смотреть назад. - person Trent Renshaw; 20.04.2020
comment
Как мое регулярное выражение не соответствует вашим требованиям? Если вы объясните лучше, я могу улучшить это - person samthegolden; 20.04.2020
comment
см. ваше регулярное выражение и тестовую строку в v2 regex101.com/r/QkK8LY/2 .. I расширили тестовую строку, чтобы дать больше контекста/ясности - person Trent Renshaw; 20.04.2020
comment
Проверьте мое редактирование @TrentRenshaw. Я не сопоставлял пробелы и варианты... Таким образом, вам не нужно указывать начальный шаблон и не нужно использовать просмотр вперед, а использовать нежадный захват. - person samthegolden; 20.04.2020