Python - Комментарии в начале строк - PullRequest
0 голосов
/ 26 января 2019

Я унаследовал некоторый код на Python 2.7, который комментировал фрагменты кода в начале каждой строки, что сводило меня с ума. Код разделен на несколько файлов и составляет> 50 тыс. Строк, поэтому я ищу способ автоматически исправить это. Не все комментарии находятся в начале строк, но некоторые есть. Я пробовал перерасчет и autopep8, но ни один из них не решит эту проблему. Вот пример:

def test_function():
    a = 1

# There are comments that are not indented!
# Usually with commented out code like this:
#    c = 5
#    if c > a:
#        a = c

    b = 5
    return a*b
print(test_function())

Иногда комментарии находятся в начале строки, даже если уровень отступа составляет 4 или 5 уровней. В идеале вышеприведенное будет преобразовано в нижеуказанное. Обратите внимание, как это включает в себя настройку пробела до и после комментария строк кода, чтобы они комментировались так, как они должны были быть. Это было бы идеально, но я бы даже был счастлив, если бы он просто добавил пробел в начале, но не корректировал его после комментария, что, вероятно, намного проще.

def test_function():
    a = 1

    # There are comments that are not indented!
    # Usually with commented out code like this:
    # c = 5
    # if c > a:
    #     a = c

    b = 5
    return a*b
print(test_function())

Кто-нибудь знает, есть ли какая-нибудь библиотека, которая может сделать это, прежде чем я пойду и попытаюсь что-то создать сам?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

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

import sys

def remove_excess_space(comments):
    """Remove excess whitespace after #"""
    excess = 0
    for line in comments:
        stripped = line.lstrip('#').lstrip()
        if excess == 0:
            excess = len(line) - len(stripped) - len('# ')
        if excess > 0:
            line = '#{}'.format(line[1 + excess:])
        yield line

def fix(filename):
    indentation = 0
    comments = []
    with open(filename, 'r') as f:
        for line in f:
            if line.startswith('#'):
                comments.append(line)
            else:
                stripped = line.lstrip()                
                if stripped and not stripped.startswith('#'):
                    # I'm assuming indentation is done with spaces, not tabs
                    indentation = len(line) - len(stripped)

                if comments:
                    # indent the comments using the same indenation as the next non-comment line
                    print(''.join(['{}{}'.format(' '*indentation, line)
                                   for line in remove_excess_space(comments)]), end='')
                    comments = []                    
                print(line, end='')

if __name__ == '__main__':
    filename = sys.argv[1]
    fix(filename)

Если мы назовем это indent_comments.py, то запустим:

indent_comments.py /path/to/script.py

печать

def test_function():
    a = 1

    # There are comments that are not indented!
    # Usually with commented out code like this:
    # c = 5
    # if c > a:
    #     a = c

    b = 5
    return a*b
print(test_function())

Обратите внимание, что в некоторых случаях этот скрипт облажается. Например, не каждая строка, начинающаяся с #, обязательно является комментарием:

print('''\
# This is not 
    a comment
''')

станет

print('''\
    # This is not 
    a comment
''')
0 голосов
/ 26 января 2019

Я собрал несколько наивный awk скрипт, который должен быть в состоянии отступить ваши комментарии:

#!/usr/bin/gawk -f
BEGIN{
    last_indent=0
}

{
    indent=match($0, /[^ ]/) - 1
    if (indent < 0) indent = 0
    comment=0
}

/^#/{
    comment=1
    if (last_indent > 0) {
        indent_str = sprintf("%*s", last_indent, " ")
        $0 = indent_str $0
    }
}

{
    print
    if (length($0) && ! comment) last_indent=indent
}

Запуск с:

$ cat src.py | ./reindent.awk

Он должен (это относится и к вашему файлу примера) напечатать входной файл питона с дополнительными пробелами, соответствующими текущему блоку, добавленному перед комментариями.

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

Излишне говорить, что в большинстве случаев комментарии следует просто отбрасывать, а оставлять их - не очень аккуратная практика, по крайней мере, поскольку у нас есть системы контроля версий для источников (так в начале 70-х годов).


В простом примере, например, это может даже привести к успешному отступу кода в комментариях:

#!/usr/bin/gawk -f
BEGIN{
    last_indent=0
    commented_code_indent = 0
}

{
    indent=match($0, /[^ ]/) - 1
    if (indent < 0) indent = 0
    comment=0
}

/^#/{
    comment=1
    if (last_indent > 0) {
        indent_str = sprintf("%*s", last_indent, " ")
    stripped = length($0)
    sub(/#  +/, "# ")
    stripped -= length($0)
    if (stripped > 0 && ! commented_code_indent) commented_code_indent = stripped
    if (commented_code_indent > 0) {
       indent_in_comment = stripped - commented_code_indent
       if (indent_in_comment > 0) {
           comment_indent_str = sprintf("%*s", indent_in_comment, " ")
           sub(/# /, "# " comment_indent_str)
       }
        }
    $0 = indent_str $0
    }
}

{
    print
    if (length($0) && ! comment) last_indent=indent
    if (! comment) commented_code_indent = 0
}

И да, если посмотреть на это сейчас, то, возможно, было бы проще, чем awk. :)

...