Как найти многострочные комментарии в кавычках? - PullRequest
2 голосов
/ 12 апреля 2020

Я анализирую Python код, и мне нужно удалить все возможные комментарии / строки документации. Я успешно смог удалить «комментарии» в форме:

#comment
"""comment""" 
'''comment''' 

Однако я нашел несколько примеров, где люди пишут комментарии в форме:

"'''comment'''" 
"\"\"\"\n comment  \"\"\""

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

p = re.compile("([\'\"])\1\1(.*?)\1{3}", re.DOTALL)
code = p.sub('', code)

Но это не сработало ни для одного из двух вторых случаев. У кого-нибудь есть предложения?

Ответы [ 3 ]

0 голосов
/ 12 апреля 2020

отправка в качестве ответа, потому что мой комментарий было трудно прочитать

Это то, что я придумал, это уродливо и хакерски, но это работает.

import re

txt = "if x = 4: continue  \"'''hi'''\"  print(x) "
print(txt)
#find everything wrapped in double quotes
double_quotes = re.findall(r"\"(.+?)\"", txt)
for string in double_quotes:
    triple_single = re.findall(r"\'''(.+?)\'''", string)[0]
    full_comment = '"'+"'''" +triple_single+"'''"+'"'
    txt = txt.replace(full_comment, '')
    print(txt)

Отпечатки:

if x = 4: continue  "'''hi'''"  print(x) 
if x = 4: continue    print(x)
0 голосов
/ 13 апреля 2020

Неназначенный строковый литерал можно рассматривать как узлы в представлении абстрактного синтаксического дерева (AST) исходного кода. Тогда проблема сводится к тому, чтобы идентифицировать эти узлы и переписать AST без них, используя инструменты модуля ast .

Комментарии (# ...) не анализируются в AST, поэтому для них не нужно кодировать.

Неназначенные строковые литералы являются узлами типа ast.Constant и являются частью атрибута body узлов, имеющих тела, такие как определения модулей, определения функций и класс определения. Мы можем идентифицировать эти узлы, удалить их из родительских body и затем переписать AST.

import ast 
import io

from unparse import Unparser


with open('comments.py') as f:
    src = f.read()

root = ast.parse(src)

# print(ast.dump(root)) to see the ast structure.


def filter_constants(node):
    if isinstance(node, ast.Expr):
        if isinstance(node.value, ast.Constant):
            if isinstance(node.value.value, str):
                return None
    return node


class CommentRemover(ast.NodeTransformer):

    def visit(self, node):
        if hasattr(node, 'body'):
            node.body = [n for n in node.body if filter_constants(n)]
        return super().visit(node)


remover = CommentRemover()
new = remover.visit(root)
ast.fix_missing_locations(new)

buf = io.StringIO()
Unparser(new, buf)
buf.seek(0)
print(buf.read())

Вызов сценария для этого кода (comments.py):

"""Module docstring."""                                                                                                             


# A real comment                                                                                                                    
"""triple-double-quote comment"""                                                                                                   
'''triple-single-quote comment'''                                                                                                   

"'''weird comment'''"                                                                                                               
"\"\"\"\n comment  \"\"\""                                                                                                          

NOT_A_COMMENT = 'spam'                                                                                                              

42                                                                                                                                  


def foo():                                                                                                                          
    """Function docstring."""                                                                                                       
    # Function comment                                                                                                              
    bar = 'baz'                                                                                                                     
    return bar                                                                                                                      


class Quux:
    """class docstring."""

    # class comment

    def m(self):
        """method comment"""
        return

Дает этот вывод:

NOT_A_COMMENT = 'spam'
42

def foo():
    bar = 'baz'
    return bar

class Quux():

    def m(self):
        return

Примечания:

  • unparse скрипт находится в папке Tools/parser вашего дистрибутива Python (в v3.8 - в предыдущие версии были в Tools или в папке Demo). Его также можно загрузить с github - . Убедитесь, что вы загружаете версию для своей версии Python
  • По состоянию на Python 3.8, класс ast.Constant используется для всех константных узлов; для более ранних версий вам может понадобиться использовать ast.Num, ast.Str, ast.Bytes, ast.NameConstant и ast.Ellipsis в зависимости от ситуации. Таким образом, в filter_constants это может выглядеть следующим образом:

    def filter_constants(node):
        if isinstance(node, ast.Expr):
            if isinstance(node.value, ast.Str):
                return None
        return node
    
  • Начиная с Python 3.9 модуль ast предоставляет функцию unparse , которая может использоваться вместо unparse скрипт

    src = ast.unparse(new)
    print(src)
    
0 голосов
/ 12 апреля 2020

Вы можете попробовать использовать strip(). Это работает, удаляя символы, которые вы помещаете между скобками. Если в скобках ничего нет, удаляются пробелы, но вы хотите удалить три одинарные кавычки, заключенные в двойные кавычки, и двойные кавычки с переносами строк. Вот пример:

txt = ",,,,,rrttgg.....banana....rrr"
x = txt.strip(",.grt")
print(x)

И вы получите «банан», поскольку он удалит ,.grt, найденный между двойными скобками (x = txt.strip(",.grt")).

Для получения дополнительной информации посетите эту страницу, и я рекомендую информацию внизу для получения дополнительной помощи: https://www.w3schools.com/python/python_strings.asp

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