Проблема с регулярным выражением:Совпадение в контексте
-
16-09-2019 - |
Вопрос
У меня есть структурированный файл с иерархическим текстом, который описывает графический интерфейс в Delphi (DFM-файл).
Давайте предположим, что у меня есть этот файл, и я должен сопоставить все строки "Color = xxx", которые находятся в контексте TmyButton (отмечены), но не те, которые находятся в другом контексте.В TMyButton-Context не будет более глубокого иерархического уровня.
object frmMain: TfrmMain
Left = 311
Top = 201
Color = clBtnFace
object MyFirstButton: TMyButton
Left = 555
Top = 301
Color = 16645072 <<<<<<MATCH THIS
OnClick = ButtonClick
end
object MyLabel: TLabel
Left = 362
Top = 224
Caption = 'a Caption'
Color = 16772831
Font.Color = clWindowText
end
object Panel2: TLTPanel
Left = 348
Top = 58
Width = 444
Height = 155
Color = clRed
object MyOtherButton: TMyButton
Left = 555
Top = 301
Color = 16645072 <<<<<<MATCH THIS
OnClick = ButtonClick
end
end
end
Я пробовал это два дня подряд, делая много-много разных попыток.Вот некоторые из моих незавершенных фрагментов узора:
/^[ ]{2,}object [A-Za-z0-9]+: TmyButton\r\n/mi <<<Matches the needed context
/^[ ]{4,}Color = [A-Za-z0-9]+\r\n/mi <<<Matches the needed result
/^[ ]{2,}end\r\n/mi <<<Matches the end of the context
(Я не знаю почему, но мне пришлось использовать " \ n" вместо "$" ...).Мне нужно собрать это воедино, но игнорируя другие строки, кроме other "object xxx:гггг" и строки "конец"....
Я был бы рад получить некоторую помощь!
Решение
Сопоставление строки в сложном контексте требует функции регулярного выражения, называемой lookaround , если вы хотите или должны сделать это с помощью одного регулярного выражения.В частности, вам понадобится lookbehind переменной длины, который PCRE не предлагает.
Итак, есть две возможности:Используйте скриптовый подход, подобный предложенному Рориком, или используйте регулярное выражение, которое соответствует всему, начиная с начала необходимого вам контекста и заканчивая фактическим совпадением, и извлеките это с помощью группы захвата.Это можно было бы сделать с помощью
[ ]{2,}object \w+: TMyButton\r\n.*?^([ ]{4,}Color = \w+[ \t]*\r\n)
(для наглядности заключите пробел в квадратные скобки).Тогда ваш матч будет в группе захвата \1
Вложенные структуры обычно плохо подходят для регулярных выражений (лучше для синтаксических анализаторов), но если вы уверены в структуре своих данных, как вы упомянули, это может сработать нормально.
Другие советы
Если я вас правильно понял, вы пытаетесь создать для этого одно регулярное выражение.Для этого нет никаких причин.
- Просто найдите линию с рисунком
object [A-Za-z0-9]+: TmyButton
- Затем сверяйте каждую следующую строку с
Color = [A-Za-z0-9]+
пока вы не найдете это или не достигнетеend
ключевое слово. - Повторяйте шаги до конца файла
Если вы попытаетесь изменить большую часть исходных файлов, вы могли бы использовать для этой цели некоторые сценарии.
Я знаю, что это не PCRE, но хорошая альтернатива для программной археологии.
Вы можете в любое время использовать AWK, если сделаете это из командной строки.Сценарий будет выглядеть примерно так:
BEGIN { inObj = 0; } // Not really necessary
/TMyButton/ { inObj = 1; }
/end$/ { inObj = 0; }
/^[ ]{4,}Color = [A-Za-z0-9]+\r\n/ && inObj == 1
{ //do whatever you need to do
print $3;
}
AWK можно найти по всему Интернету.Я бы попробовал ПОГЛАЗЕТЬ.