2015-07-13 3 views
4

мне нужно искать что-то вроде этого:питона обратной ссылки регулярного выражению

lines = """package p_dio_bfm is 
    procedure setBFMCmd ( 
     variable pin : in tBFMCmd 
    ); 
end p_dio_bfm; -- end package; 

package body p_dio_bfm is 
    procedure setBFMCmd ( 
     variable pin : in tBFMCmd 
    ) is 
    begin 
     bfm_cmd := pin; 
    end setBFMCmd; 
end p_dio_bfm;""" 

Мне нужно извлечь имя пакета, т.е. p_dio_bfm и объявление пакета, то есть часть между «пакетом p_dio_bfm является» и FIRST «конец p_dio_bfm ;»

Проблема в том, что объявление пакета может заканчиваться на «end p_dio_bfm;» или "конечный пакет"; Поэтому я попробовал следующее «OR» регулярное выражение, которое: - работает для пакетов, заканчивающихся «end package» - не работает для пакетов, заканчивающихся «end pck_name;»;

pattern = re.compile("package\s+(\w+)\s+is(.*)end\s+(package|\1)\s*;") 
match = pattern.search(lines) 

Проблема заключается в том (пакете | \ 1) часть регулярного выражения, где я, что поймать или слово «пакет» или совпадающее имя пакета.

UPDATE: Я представил полный код, который я надеюсь, прояснит его:

import re 
lines1 = """package p_dio_bfm is 
    procedure setBFMCmd (
     variable pin : in tBFMCmd 
    ); 
end p_dio_bfm; 

package body p_dio_bfm is 
    procedure setBFMCmd (
     variable pin : in tBFMCmd 
    ) is 
    begin 
     bfm_cmd := pin; 
    end setBFMCmd; 
end p_dio_bfm;""" 

lines2 = """package p_dio_bfm is 
    procedure setBFMCmd (
     variable pin : in tBFMCmd 
    ); 
end package; 

package body p_dio_bfm is 
    procedure setBFMCmd (
     variable pin : in tBFMCmd 
    ) is 
    begin 
     bfm_cmd := pin; 
    end setBFMCmd; 
end package;""" 

lines1 = lines1.replace('\n', ' ') 
print lines1 

pattern = re.compile("package\s+(\w+)\s+is(.*)end\s+(package|\1)\s*;") 
match = pattern.search(lines1) 

print match 

lines2 = lines2.replace('\n', ' ') 
print lines2 

match = pattern.search(lines2) 

print match 

Я ожидаю, что в обоих случаях, используя уникальный регулярное выражение, чтобы получить обратно эту часть:

"""procedure setBFMCmd (
      variable pin : in tBFMCmd 
     );""" 

без \ n символов, которые я удалил.

+0

Можете ли вы опубликовать ожидаемый результат? –

ответ

2

Как насчет:

>>> for row in re.findall(
... r'package(?:\s.*?)(?P<needle>[^\s]+)\s+is\s+(.*?)end\s+(?:package|(?P=needle));', 
... lines, 
... re.S 
...): 
... print '{{{', row[1], '}}}' 
... 
{{{ procedure setBFMCmd (
     variable pin : in tBFMCmd 
    ); 
}}} 
{{{ procedure setBFMCmd (
     variable pin : in tBFMCmd 
    ) is 
    begin 
     bfm_cmd := pin; 
    end setBFMCmd; 
}}} 

Я взял на себя смелость, чтобы не фильтровать, как именно @ Mihai-hangiu спросил, включив второй блок.

+0

Он работал, как я и ожидал. Спасибо. –

3

Ваше регулярное выражение ничего не соответствует, так как это incorrect.Without используя многострочный флаг .* не будет соответствовать новой строки, так что вместо этого вы можете использовать [\s\S]*:

r'package ([^\s]+)\s+is([\s\S]*)end\s+(package|\1)\s*;' 

См демо https://regex101.com/r/tZ3uH0/1

Но есть и некоторые другие проблемы, связанные с тем, что ваша строка содержит 2 блока блоков, и этот момент, который является более элегантным и эффективным способом, вы можете подать в суд на флаг re.DOTALL, который делает '.' специальный символ соответствует любому символу на всех, в том числе newline.So вы можете написать регулярное выражение, как следующее:

pattern = re.compile("package\s+(\w+)\s+is(.*)end\s+(package|\1)\s*;",re.DOTALL) 

Но это все еще будет соответствовать первому блоку:

>>> match = pattern.search(lines) 
>>> print match.group(0) 
package p_dio_bfm is 
    procedure setBFMCmd ( 
     variable pin : in tBFMCmd 
    ); 
end p_dio_bfm; -- end package; 
>>> print match.group(1) 
p_dio_bfm 
>>> print match.group(2) 

    procedure setBFMCmd ( 
     variable pin : in tBFMCmd 
    ); 
end p_dio_bfm; -- 
>>> print match.group(3) 
package 

Для матча всех блоков, которые нужно уточнить такие слова, как body во второй группе:

package\s+(?:\w+\s+?)?([^\s]+)\s+is(.*?)end\s+(package|\1)\s*; 

Смотрите демо https://regex101.com/r/tZ3uH0/3

+0

Я не вижу смысла использовать '[\ s \ S]' вместо '.' с' re.S'. Вам не нужно иметь дело с определением конкретной линии здесь, не так ли? Если регулярное выражение не нуждается в портировании, чтобы сказать JavaScript, я считаю, что более эффективно использовать «встроенные» средства для соответствия новостям. –

+0

@ Kasra, разве OP не сказал: * между «пакетом p_dio_bfm is» и FIRST «end p_dio_bfm;» *? –

+0

Вы можете воспользоваться [названными ссылками] (https://docs.python.org/2/library/re.html): '(? P ^\ s +) \ s ... (пакет | (?Р = игла)) '. – bufh

Смежные вопросы