Рассмотрим следующую простую текстовую информацию:
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
Любой простой способ сделать это?
Если вы хотите игнорировать разделы, отличные от тех, которые имеют val=1
, вы можете использовать здесь следующее.
(?s)(start((?!val=\d+).)*val=1\b.*?end)
ОБНОВЛЕНИЕ:
Чтобы ответить на обновленное редактирование, вы можете использовать следующие для захвата этих разделов.
(?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
Проблема, которая у вас есть, которая не захвачена вводом примера, заключается в том, что перед тем, как вы хотите, есть начальный/конечный блок, потому что наивное регулярное выражение, даже используя кванторы с неохотой, будет совпадать при первом запуске до целевого значения.
Решение состоит в том, чтобы максимально использовать вход до матча:
.*(start.*?val=1\b.*?end)
См. Живую демоверсию, у которой есть дополнительный блок перед целью, который фиксируется как группа 1.
Это регулярное выражение, которое должно использоваться с флагом "dotall", фиксирует ваш целевой блок как группу 1. ". *" Спереди - это небольшая, но важная часть, которая потребляет любые блоки, которые могут предшествовать вашей цели.
Вы можете быть более строгим, если при необходимости использовать границы слов \b
вокруг различных частей. Граница слов, вероятно, рекомендуется после целевого номера, поэтому входные данные, такие как val=12
, случайно не совпадают.
Если вы просто хотите найти, что между start\s+val=1
и end
, вы можете использовать что-то простое, например:
(?s)\bstart\s+val=1\b(.*?)\bend\b
Где вы могли бы заменить val=1
любым интересующим вас шаблоном.