Подтвердить что ты не робот

Использование regex для удаления комментариев из исходных файлов

Я создаю программу для автоматизации написания некоторого кода на C (я пишу для синтаксического анализа строк в одноименные перечисления) C обработка строк не так уж велика. Поэтому некоторые люди навязывают мне попробовать python.

Я сделал функцию, которая должна удалить C-стиль /* COMMENT */ и //COMMENT из строки: Вот код:

def removeComments(string):
    re.sub(re.compile("/\*.*?\*/",re.DOTALL ) ,"" ,string) # remove all occurance streamed comments (/*COMMENT */) from string
    re.sub(re.compile("//.*?\n" ) ,"" ,string) # remove all occurance singleline comments (//COMMENT\n ) from string

Итак, я попробовал этот код.

str="/* spam * spam */ eggs"
removeComments(str)
print str

И он ничего не сделал.

Любые предложения относительно того, что я сделал неправильно?

Там высказывание, которое я слышал пару раз:

Если у вас есть проблема, и вы пытаетесь решить ее с помощью Regex, у вас возникнут две проблемы.


EDIT: Оглядываясь назад на эти годы позже. (после справедливого более сильного анализа)

Я думаю, что регулярное выражение, возможно, было правильным решением. И простое регулярное выражение используется здесь "достаточно хорошо". Возможно, я не подчеркнул этого в вопросе. Это было для одного конкретного файла. У этого не было сложных ситуаций. Я думаю, что было бы намного меньше обслуживания, чтобы файл анализировался достаточно просто для регулярного выражения, чем для усложнения регулярного выражения в нечитаемый суп символа.

4b9b3361

Ответ 1

re.sub возвращает строку, поэтому изменение вашего кода на следующее даст результаты:

def removeComments(string):
    string = re.sub(re.compile("/\*.*?\*/",re.DOTALL ) ,"" ,string) # remove all occurrences streamed comments (/*COMMENT */) from string
    string = re.sub(re.compile("//.*?\n" ) ,"" ,string) # remove all occurrence single-line comments (//COMMENT\n ) from string
    return string

Ответ 2

Многие ответы уже даны, но; как насчет "//comment-like strings inside quotes"?

OP спрашивает, как это сделать, используя регулярные выражения; так:

def remove_comments(string):
    pattern = r"(\".*?\"|\'.*?\')|(/\*.*?\*/|//[^\r\n]*$)"
    # first group captures quoted strings (double or single)
    # second group captures comments (//single-line or /* multi-line */)
    regex = re.compile(pattern, re.MULTILINE|re.DOTALL)
    def _replacer(match):
        # if the 2nd group (capturing comments) is not None,
        # it means we have captured a non-quoted (real) comment string.
        if match.group(2) is not None:
            return "" # so we will return empty to remove the comment
        else: # otherwise, we will return the 1st group
            return match.group(1) # captured quoted-string
    return regex.sub(_replacer, string)

Удалить WILL:

  • /* multi-line comments */
  • // single-line comments

НЕ будет удалять:

  • String var1 = "this is /* not a comment. */";
  • char *var2 = "this is // not a comment, either.";
  • url = 'http://not.comment.com';

Примечание. Это также будет работать для источника Javascript.

Ответ 3

Я бы предложил использовать парсер REAL, например SimpleParse или PyParsing. SimpleParse требует, чтобы вы действительно знали EBNF, но очень быстро. PyParsing имеет свой собственный синтаксис, подобный EBNF, но адаптированный для Python и делает его легким для создания мощных точных парсеров.

Изменить:

Вот пример того, как легко использовать PyParsing в этом контексте:

>>> test = '/* spam * spam */ eggs'
>>> import pyparsing
>>> comment = pyparsing.nestedExpr("/*", "*/").suppress()
>>> print comment.transformString(test)         
' eggs'

Вот более сложный пример, использующий одиночные и многострочные комментарии.

До:

/*
 * multiline comments
 * abc 2323jklj
 * this is the worst C code ever!!
*/
void
do_stuff ( int shoe, short foot ) {
    /* this is a comment
     * multiline again! 
     */
    exciting_function(whee);
} /* extraneous comment */

После:

>>> print comment.transformString(code)   

void
do_stuff ( int shoe, short foot ) {

     exciting_function(whee);
} 

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

Ответ 4

Я бы порекомендовал вам прочитать эту страницу, которая содержит довольно подробный анализ проблемы и дает хорошее представление о том, почему ваш подход не работает: http://ostermiller.org/findcomment.html

Короткая версия: Регулярное выражение, которое вы ищете, следующее:

(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)

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

Ответ 5

Вы делаете это неправильно.

Regex для Regular Languages ​​, который C не является.

Ответ 6

Я вижу несколько вещей, которые вы, возможно, захотите пересмотреть.

Во-первых, Python передает объекты по значению, но некоторые типы объектов неизменяемы. Строки и целые числа относятся к этим неизменяемым типам. Поэтому, если вы передаете строку функции, любые изменения в строке, которые вы вносите в функцию, не будут влиять на строку, в которую вы передали. Вместо этого вы должны попробовать вернуть строку. Кроме того, в функции removeComments() вам нужно присвоить значение, возвращенное re.sub(), новой переменной - подобно любой функции, которая принимает строку в качестве аргумента, re.sub() не будет изменять строку.

Во-вторых, я бы сказал, что другие говорили о разборе кода C. Регулярные выражения - не лучший способ пойти сюда.

Ответ 7

mystring="""
blah1 /* comments with
multiline */

blah2
blah3
// double slashes comments
blah4 // some junk comments

"""
for s in mystring.split("*/"):
    s=s[:s.find("/*")]
    print s[:s.find("//")]

Выход

$ ./python.py

blah1


blah2
blah3

Ответ 8

Как отмечено в одном из моих других комментариев, вложение комментариев на самом деле не проблема (в C комментарии не гнездятся, хотя несколько компиляторов поддерживают вложенные комментарии в любом случае). Проблема связана с такими вещами, как строковые литералы, которые могут содержать точно такую ​​же последовательность символов, что и разделитель комментариев, фактически не являясь одним из них.

Как сказал Майк Грэм, правильным инструментом для работы является лексер. Парсер не нужен и будет излишним, но лексер - это именно то, что нужно. Как это происходит, я опубликовал (частичный) lexer для C (и С++) ранее утром. Он не пытается правильно идентифицировать все лексические элементы (т.е. Все ключевые слова и операторы), но это вполне достаточно для снятия комментариев. Он не будет делать ничего хорошего на "использовании Python", хотя, поскольку он полностью написан на C (он предшествует моему использованию С++ для гораздо большего, чем экспериментальный код).

Ответ 9

Эта программа удаляет комментарии с//и/* */из заданного файла:

#! /usr/bin/python3
import sys
import re
if len(sys.argv)!=2:
     exit("Syntax:python3 exe18.py inputfile.cc ")
else:
     print ('The following files are given by you:',sys.argv[0],sys.argv[1])
with open(sys.argv[1],'r') as ifile:
    newstring=re.sub(r'/\*.*?\*/',' ',ifile.read(),flags=re.S)
with open(sys.argv[1],'w') as ifile:
    ifile.write(newstring)
print('/* */ have been removed from the inputfile')
with open(sys.argv[1],'r') as ifile:
      newstring1=re.sub(r'//.*',' ',ifile.read())
with open(sys.argv[1],'w') as ifile:
      ifile.write(newstring1)
print('// have been removed from the inputfile')

Ответ 10

Просто хочу добавить еще одно регулярное выражение, где мы должны удалить что-нибудь между * и; в питоне

data = re.sub(re.compile("*. *? \;", re.DOTALL), '', data)

перед * стоит косая черта, чтобы избежать метасимвола.