Поиск назад через строку с помощью регулярного выражения (в Python)? - PullRequest
1 голос
/ 20 марта 2010

Context
Я анализирую некоторый код и хочу сопоставить комментарии doxygen перед функцией. Однако из-за того, что я хочу сопоставить определенное имя функции, получение только предыдущего комментария вызывает у меня проблемы.

Текущий подход

import re  
function_re = re.compile(
    r"\/\*\*(.+)\*\/\s*void\s+(\w+)\s*::\s*function_name\s*\(\s*\)\s*")  
function_match = function_re.search(file_string)
if function_match:  
    function_doc_str = update_match.group(2)

Проблема с текущим подходом
Текущий подход сопоставляет doxygen с более ранними функциями, давая мне результат, который является неправильным комментарием doxygen.

Вопрос
Есть ли способ поиска в обратном направлении через строку с помощью библиотеки Python Regex?
Похоже, моя проблема в том, что более ограничительной (менее часто встречающейся частью) является сигнатура функции "void function ()"

Возможно, лучший вопрос
Есть ли лучший (более простой) подход, который мне не хватает?

Ответы [ 7 ]

2 голосов
/ 20 марта 2010

Я думаю, что вы должны использовать регулярное выражение, совпадающее только с доксиментацией непосредственно перед функцией. Может быть, что-то вроде этого (упрощенный пример):

import re

test = """

/**
    @doxygen comment
*/
void function()
{
}

"""

doxygenRegex = r"(?P<comment>/\*\*(?:[^/]|/(?!\*\*))*\*/)"
functionRegex = r"(?P<function>\s\w+\s+(?P<functionName>\w+)\s*\()"

match = re.search(doxygenRegex + functionRegex, test)
print match.groupdict()

Пока это соответствует чему-либо, вы можете зацикливать совпадение с регулярным выражением - но в следующий раз начнете поиск с test[match.end():]. Надеюсь, что это имеет смысл для вас ...

Кстати, если вы хотите извлечь только комментарий и ничего о функции, вы можете использовать lookahead - просто замените functionRegex на r"(?=\s\w+\s+\w+\s*\()".

2 голосов
/ 20 марта 2010

Это может быть достигнуто с помощью одного регулярного примера.

Ключ заключается в захвате комментария непосредственно перед желаемой функцией. Самый простой способ сделать это - использовать не жадный квалификатор. Например: /\*\*(.*?)\*/ с флагом MULTILINE; однако в Python не-жадные и MULTILINE не работают вместе (по крайней мере, в моей среде). Итак, вам нужен маленький трюк, подобный этому:

/\*\*((?:[^\*]|\*(?!/))*)\*/.

Это соответствует:

1: комментарий начинается /**.

2: все, что не * ИЛИ *, что не следует /

3: конец комментария */.

Исходя из этой идеи, вам нужен код:

function_name  = "function2"
regex_comment  = "/\*\*((?:[^\*]|\*(?!/))*)\*/"
regex_static   = "(?:(\w+)\s*::\s*)?"
regex_function = "(\w+)\s+"+regex_static+"(?:"+function_name+")\s*\([^\)]*\)"
regex = re.compile(regex_comment+"\s*"+regex_function, re.MULTILINE)
text  = """
/**
    @doxygen comment1
*/
void test::function1()
{
}

/**
    @doxygen comment2
*/
void test::function2()
{
}
"""
match = regex.search(text)
if (match == None): print "None"
else:               print match.group(1)

При запуске вы получаете:


    @doxygen comment2

Изменение: Если вы хотите захватить /** и */, используйте regex_comment = "(/\*\*(?:[^\*]|\*(?!/))*\*/)".

Надеюсь, это поможет.

2 голосов
/ 20 марта 2010

Самый простой способ - это просто использовать группу, вам не нужно возвращаться назад ...

 (commentRegex)functionRegex

Затем просто извлеките группу 1. Вам нужно будет запустить ее в многострочном режиме, чтобы я работал, я не знаю python, поэтому не могу быть более полезным.

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

1 голос
/ 20 марта 2010

Обратите внимание, что C не является регулярным языком, поэтому он не может быть проанализирован регулярными выражениями. Вы рассматривали возможность использования самого doxygen для анализа этого файла?

0 голосов
/ 20 марта 2010

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

test = """

/**
    @doxygen comment
*/
void function()
{
}

"""

t=test.split("*/")
for n,comm in enumerate(t):
    try:
        if "void" in t[n+1]:
             print t[n]
    except IndexError: pass
0 голосов
/ 20 марта 2010

Вопрос в том, почему эти комментарии не находятся внутри функции, поэтому вы можете использовать doc .

Но с регулярным выражением нет простого пути.

0 голосов
/ 20 марта 2010

Вы можете делать утверждения с помощью (?<=...) или (?<!...), но в целом вы можете сопоставлять только нападающие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...