2015-04-19 2 views
0

Я хочу извлечь несколько блоков текста, используя регулярное выражение. Мое регулярное выражение получает правильное начало, но также возвращает все до конца моего файла.VBS regex extract mutiple blocks

Я использую:

re.ignorecase = true 
re.multiline = false 
re.global = true 
re.pattern = "\balias\s=\sX[\s\S]{1,}end" 

качестве примера формат файла:

Metadata Begin 
    Easting Begin 
     alias = X 
     projection = "geodetic" 
     datum = "GDA94" 
    Easting End 
    Northing Begin 
     alias = Y 
     projection = "geodetic" 
     datum = "GDA94" 
    Northing End 
Metadata End 

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

alias = X 
    projection = "geodetic" 
    datum = "GDA94" 
Easting End 

Но это не получает первый End после alias. Вместо этого [\s\S] сопоставляет все после первого alias до конца файла. Но [\s\S] - единственный трюк, который я могу представить, чтобы пройти мимо CrLf в конце каждой строки.

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

ответ

2

Вам нужно не жадное регулярное выражение. [\s\S]{1,} жадный, который соответствует всем персонажам как можно больше. Чтобы заставить этот шаблон остановиться, как только он найдет совпадение совпадений, вам нужно добавить нежирный квантор ? рядом с {1,}. Так было бы [\s\S]{1,}?. Это может быть написано даже в более простой форме как [\s\S]+?.

re.pattern = "\balias\s=\sX[\s\S]+?end" 

Добавить \b до и после того, как к строке end, если это необходимо.

DEMO

1

Я хотел бы предложить многоступенчатый подход.

  1. одного из блоков:

    (Easting|Northing) Begin([\s\S]*?)\1 End 
    
  2. Процесс их содержание построчно

    (\S+)\s+=\s+("?)(.*)\2 
    

Таким образом, если положить вместе, мы получаем

Option Explicit 

Dim reBlock, reLine, input 
Dim blockType, blockBody, name, value 

Set reBlock = New RegExp 
Set reLine = New RegExp 

input = LoadYourFile() 

reBlock.Pattern = "(Easting|Northing) Begin([\s\S]*?)\1 End" 
reBlock.Global = True 
reBlock.IgnoreCase = True 

reLine.Pattern = "(\S+)\s+=\s+(""?)(.*)\2" 
reLine.Global = True 
reLine.IgnoreCase = True 

For Each block In reBlock.Execute(input) 
    blockType = block.SubMatches(0) 
    blockBody = block.SubMatches(1) 
    For Each line In reLine.Execute(blockBody) 
     name = line.SubMatches(0) 
     value = line.SubMatches(2) 
     WScript.Echo blockType & ": " & name & " = " & value 
    Next 
Next 

Особенностями

  • нежадным соответствия, как описано в разделе @ AvinashRaj отвечают.
  • обратные ссылки в пределах регулярного выражение
  • структурированного подход позволяет легко вывод контекстной информации (то есть «какой блок имеет это значение принадлежит?»)
+0

Спасибо за обширный пример. – user1502755