2014-12-09 5 views
-1

Как я могу захватить класс и методы из файла python?Regex для захвата класса и методов

Меня не интересуют attrs или args.

class MyClass_1(...): 
    ... 
    def method1_of_first_class(self): 
     ... 

    def method2_of_first_class(self): 
     ... 

    def method3_of_first_class(self): 
     ... 

class MyClass_2(...): 
    ... 
    def method1_of_second_class(self): 
     ... 

    def method2_of_second_class(self): 
     ... 

    def method3_of_second_class(self): 
     ... 

То, что я пытался до сих пор:

class ([\w_]+?)\(.*?\):.*?(?:def ([\w_]+?)\(self.*?\):.*?)+?

Варианты: точка соответствует новой строки

захватывая КЛАССА

Match the characters “class ” literally «class » 
Match the regular expression below and capture its match into backreference number 1 «([\w_]+?)» 
    Match a single character present in the list below «[\w_]+?» 
     Between one and unlimited times, as few times as possible, expanding as needed (lazy) «+?» 
     A word character (letters, digits, etc.) «\w» 
     The character “_” «_» 
Match the character “(” literally «\(» 
Match any single character «.*?» 
    Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?» 
Match the character “)” literally «\)» 
Match the character “:” literally «:» 
Match any single character «.*?» 
    Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?» 

захватывая МЕТОДЫ:

Match the regular expression below «(?:def ([\w_]+?)\(self.*?\):.*?)+?» 
    Between one and unlimited times, as few times as possible, expanding as needed (lazy) «+?» 
    Match the characters “def ” literally «def » 
    Match the regular expression below and capture its match into backreference number 2 «([\w_]+?)» 
     Match a single character present in the list below «[\w_]+?» 
     Between one and unlimited times, as few times as possible, expanding as needed (lazy) «+?» 
     A word character (letters, digits, etc.) «\w» 
     The character “_” «_» 
    Match the character “(” literally «\(» 
    Match the characters “self” literally «self» 
    Match any single character «.*?» 
     Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?» 
    Match the character “)” literally «\)» 
    Match the character “:” literally «:» 
    Match any single character «.*?» 
     Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?» 

Но это только захватывает имя класса и первый метод, я думаю, что это потому, что обратная ссылка номер 2 не может захватить больше чем 1, даже то, что находится внутри (? Myregex) +?

Выходной ток:

'MyClass_1':'method1_of_first_class', 
'MyClass_2':'method1_of_second_class' 

Желаемая Выход:

'MyClass_1':['method1_of_first_class','method2_of_first_class',...], 
'MyClass_2':['method1_of_second_class','method2_of_second_class',...] 
+0

Каков ваш ожидаемый результат? –

+0

'[MyClass_1, [method1_of_first_class, method2_of_first_class, ...]]' '[MyClass_2, [method1_of_second_class, method2_of_second_class, ...]]' –

+1

Анализ кода с регулярным выражением ** жесткий **. См. [1] (http://stackoverflow.com/a/27149898/), [2] (http://stackoverflow.com/a/17134110), [3] (http://stackoverflow.com/a/ 21395083). Я бы предложил использовать выделенный парсер. Также, задавая вопросы регулярного выражения, укажите язык/инструмент, который вы используете. – HamZa

ответ

2

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

В частности, pydoc.py (который доступен из версии 2.1) в вашей установке Python является ярким примером таких случаев.

код Синтаксический Python в Python прост, так как Python включает в себя модуль встроенный парсер в parser модуле и (начиная с версии 2.6) ast.

Это пример кода для синтаксического анализа кода Python в Python с ast модулем (версии 2.6 и выше.):

from ast import * 
import sys 

fi = open(sys.argv[1]) 
source = fi.read() 
fi.close() 

parse_tree = parse(source) 

class Node: 
    def __init__(self, node, children): 
     self.node = node; 
     self.children = children 

    def __repr__(self): 
     return "{{{}: {}}}".format(self.node, self.children) 

class ClassVisitor(NodeVisitor): 
    def visit_ClassDef(self, node): 
     # print(node, node.name) 

     r = self.generic_visit(node) 
     return Node(("class", node.name), r) 

    def visit_FunctionDef(self, node): 
     # print(node, node.name) 

     r = self.generic_visit(node) 
     return Node(("function", node.name), r) 


    def generic_visit(self, node): 
     """Called if no explicit visitor function exists for a node.""" 
     node_list = [] 

     def add_child(nl, children): 
      if children is None: 
       pass 
       ''' Disable 2 lines below if you need more scoping information ''' 
      elif type(children) is list: 
       nl += children 
      else: 
       nl.append(children) 

     for field, value in iter_fields(node): 
      if isinstance(value, list): 
       for item in value: 
        if isinstance(item, AST): 
         add_child(node_list, self.visit(item)) 
      elif isinstance(value, AST): 
       add_child(node_list, self.visit(value)) 

     return node_list if node_list else None 

print(ClassVisitor().visit(parse_tree)) 

Код был протестирован в Python 2.7 и Python 3.2.

Поскольку реализация по умолчанию generic_visit ничего не возвращает, я скопировал источник generic_visit и изменил его, чтобы передать возвращаемое значение обратно вызывающему.

0

Вы можете использовать this regex начать с:

/class\s(\w+)|def\s(\w+)/gm 

Это будет соответствовать все имена классов и методов. Чтобы получить его в структуре, о которой вы упомянули в своих комментариях, вам, вероятно, потребуется использовать язык реализации.

Изменить:here's a PHP implementation example:

$output = array(); 

foreach ($match_array[0] as $key => $value) { 
    if (substr($value, 0, 5) === 'class') { 
     $output[$value] = array(); 
     $parent_key = $value; 
     continue; 
    } 
    $output[$parent_key][] = $value; 
} 

// print_r($output); 

foreach ($output as $parent => $values) { 
    echo '[' . $parent . ', [' . implode(',', $values) . ']]' . PHP_EOL; 
} 

Пример вывода:

[class MyClass_1, [def method1_of_first_class,def method2_of_first_class,def method3_of_first_class]] 
[class MyClass_2, [def method1_of_second_class,def method2_of_second_class,def method3_of_second_class]] 
+0

Черт, я чувствую себя глупо, потому что не думаю об этом. –

+0

Это пример. До вас и на каком языке вы используете это. –

+1

@ f.rodrigues, просто имейте в виду, что это решение не будет работать для ввода, содержащего строку со словом 'class' или' def' в нем. то есть "" "" класс, который делает что-то "" "", будет искать класс под названием 'that'. Более надежным решением было бы предложение nhahtdh. –

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