Я унаследовал некоторый код 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())
Кто-нибудь знает, есть ли уже какая-то библиотека, которая может это сделать, прежде чем я пойду и попытаюсь что-то создать самостоятельно?
Это больше похоже на заброшенный код. Также похоже, что кто-то не использовал контроль версий. Покрывается ли он тестами?
Во втором примере вы должны удалить «#» из строк кода (удалить # и пробел). Это поддерживает совместимость с pep8, которой я обычно придерживаюсь. Удалить «#» в начале строки так же просто, как и «#».
Да, это заброшенный код, и я планирую его очистить, но мне нужно попытаться понять, почему код был заброшен, и очистить его (в свое время). Код сейчас не в лучшей форме, и он не контролируется версиями. Я также планирую переместить его в репозиторий git, когда смогу.
Я собрал несколько наивный скрипт 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
Он должен (это делается для вашего примера файла) распечатать входной файл python с дополнительными пробелами, соответствующими текущему блоку, добавленному к комментариям.
Я рассмотрел ваш дополнительный запрос на корректировку кода в комментарии, но это крайне нетривиально, поскольку на самом деле скрипт должен иметь приличный уровень понимания того, что он обрабатывает.
Излишне говорить, что комментарии в большинстве случаев должны быть просто удалены, а оставлять их - не очень аккуратная практика, по крайней мере, поскольку у нас есть системы контроля версий для исходников (начало 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. :)
Спасибо, я попробую, когда снова буду перед кодом. Да, я согласен с тем, что закомментированный код должен быть удален, а вместо этого должен контролироваться версия. Я планирую это сделать, но в данный момент я просто пытаюсь обхватить это своими руками.
Строки, начинающиеся с #
, отступают так, чтобы они соответствовали тому же уровню отступа, что и следующая строка без комментариев:
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
''')
Спасибо, я попробую это, когда снова буду перед кодом. Спасибо и за предупреждения по угловым случаям.
если вы удалите только
#
в начале, отступ будет в порядке с вашим первым примером. Если вы сделаете это во втором примере, это уничтожит программу.