RegEx: Как захватить подраздел

1

Рассмотрим следующую простую текстовую информацию:

info
  start
    date=20140521
    val=key1
    info="Just a string"
  end

  start
    date=20140521
    val=key2
    info="Another one"
  end
end

Я хотел бы захватить раздел, основанный на значении поля 'val', используя RegEx.

Для примера предположим, что я хотел бы получить val = key1.

После регулярного выражения ничего не захватывает!

(start((?=val=key1)(.|\s))*?end)

Однако, если я использую следующий, я могу захватить раздел, который имеет val = key2 (напротив того, что я хочу)

(start((?!val=key1)(.|\s))*?end)

Вот раздел, захваченный в этом случае:

  start
    date=20140521
    val=key2
    info="Another one"
  end

Любой простой способ сделать это?

Теги:

3 ответа

2
Лучший ответ

Если вы хотите игнорировать разделы, отличные от тех, которые имеют val=1, вы можете использовать здесь следующее.

(?s)(start((?!val=\d+).)*val=1\b.*?end)

Live Demo

ОБНОВЛЕНИЕ:

  • Чтобы ответить на обновленное редактирование, вы можете использовать следующие для захвата этих разделов.

    (?s)(start((?!val=\w+).)*val=key1\b.*?end)
    

    Регулярное выражение:

    (?s)           set flags for this block (with . matching \n)
    (              group and capture to \1:
     start         'start'
     (             group and capture to \2 (0 or more times)
     (?!           look ahead to see if there is not:
      val=         'val='
       \w+         word characters (a-z, A-Z, 0-9, _) (1 or more times)
     )             end of look-ahead
     .             any character
     )*            end of \2 
     val=key1      'val=key1'
       \b          the boundary between a word char (\w) and not a word char
     end           'end'
    )              end of \1
    

    Live Demo

  • 0
    +1 Очень хороший ответ. Я должен был сделать значения более общими, а не числовыми.
  • 1
    @ omt66 Смотрите обновленный ответ.
Показать ещё 1 комментарий
0

Проблема, которая у вас есть, которая не захвачена вводом примера, заключается в том, что перед тем, как вы хотите, есть начальный/конечный блок, потому что наивное регулярное выражение, даже используя кванторы с неохотой, будет совпадать при первом запуске до целевого значения.

Решение состоит в том, чтобы максимально использовать вход до матча:

.*(start.*?val=1\b.*?end)

См. Живую демоверсию, у которой есть дополнительный блок перед целью, который фиксируется как группа 1.

Это регулярное выражение, которое должно использоваться с флагом "dotall", фиксирует ваш целевой блок как группу 1. ". *" Спереди - это небольшая, но важная часть, которая потребляет любые блоки, которые могут предшествовать вашей цели.

Вы можете быть более строгим, если при необходимости использовать границы слов \b вокруг различных частей. Граница слов, вероятно, рекомендуется после целевого номера, поэтому входные данные, такие как val=12, случайно не совпадают.

0

Если вы просто хотите найти, что между start\s+val=1 и end, вы можете использовать что-то простое, например:

(?s)\bstart\s+val=1\b(.*?)\bend\b

Где вы могли бы заменить val=1 любым интересующим вас шаблоном.

  • 0
    Спасибо за ответ, очень полезный на деле. Тем не менее, я хотел бы захватить от начала до конца, потому что могут быть другие поля между start и val = x.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню