4

I want to delete all comment in python file. file like this: --------------- comment.py ---------------

# this is comment line.
age = 18  # comment in line
msg1 = "I'm #1."  # comment. there's a # in code.
msg2 = 'you are #2. ' + 'He is #3'  # strange sign ' # ' in comment. 
print('Waiting your answer')

I write many regex to extract all comments, some like this:

(?(?<=['"])(?<=['"])\s*#.*$|\s*#.*$)
get:  #1."  # comment. there's a # in code.

(?<=('|")[^\1]*\1)\s*#.*$|\s*#.*$
wrong. it's not 0-width in lookaround (?<=..)

But it dosn't work right. What's the right regex? Could you help me, please?

Toto
  • 89,455
  • 62
  • 89
  • 125
Mal Sund
  • 78
  • 7
  • 1
    You probably would not to write a parser to handle all these edge cases correctly. – Tim Biegeleisen Jun 11 '20 at 03:01
  • 2
    Parsing code using regex is bad idea. As a result you will get huge expression which is really slow. – Olvin Roght Jun 11 '20 at 03:16
  • Thanks for your advice. I want give up yestoday, and write `\s*#[^'"]*$` for usual cases. but python idle can resolve all cases, i don't know if python idle use regex? – Mal Sund Jun 11 '20 at 03:29

2 Answers2

1

You can try using tokenize instead of regex, as @OlvinRoght said, parsing code using regex maybe is bad idea in this case. As you can see here, you can try something like this to detect the comments:

import tokenize
fileObj = open('yourpath\comment.py', 'r')
for toktype, tok, start, end, line in tokenize.generate_tokens(fileObj.readline):
    # we can also use token.tok_name[toktype] instead of 'COMMENT'
    # from the token module 
    if toktype == tokenize.COMMENT:
        print('COMMENT' + " " + tok)

Output:

COMMENT # -*- coding: utf-8 -*-
COMMENT # this is comment line.
COMMENT # comment in line
COMMENT # comment. there's a # in code.
COMMENT # strange sign ' # ' in comment.

Then, to get the expected result, that is python file without comments, you can try this:

nocomments=[]
for toktype, tok, start, end, line in tokenize.generate_tokens(fileObj.readline):
    if toktype != tokenize.COMMENT:
        nocomments.append(tok)

print(' '.join(nocomments))

Output:

 age = 18 
 msg1 = "I'm #1." 
 msg2 = 'you are #2. ' + 'He is #3' 
 print ( 'Waiting your answer' )  
MrNobody33
  • 6,413
  • 7
  • 19
1

Credit: https://gist.github.com/BroHui/aca2b8e6e6bdf3cb4af4b246c9837fa3

This will do. It uses tokenize. You can modify this code as per your use.

""" Strip comments and docstrings from a file.
"""

import sys, token, tokenize

def do_file(fname):
    """ Run on just one file.
    """
    source = open(fname)
    mod = open(fname + ",strip", "w")

    prev_toktype = token.INDENT
    first_line = None
    last_lineno = -1
    last_col = 0

    tokgen = tokenize.generate_tokens(source.readline)
    for toktype, ttext, (slineno, scol), (elineno, ecol), ltext in tokgen:
        if 0:   # Change to if 1 to see the tokens fly by.
            print("%10s %-14s %-20r %r" % (
                tokenize.tok_name.get(toktype, toktype),
                "%d.%d-%d.%d" % (slineno, scol, elineno, ecol),
                ttext, ltext
                ))
        if slineno > last_lineno:
            last_col = 0
        if scol > last_col:
            mod.write(" " * (scol - last_col))
        if toktype == token.STRING and prev_toktype == token.INDENT:
            # Docstring
            mod.write("#--")
        elif toktype == tokenize.COMMENT:
            # Comment
            mod.write("\n")
        else:
            mod.write(ttext)
        prev_toktype = toktype
        last_col = ecol
        last_lineno = elineno

if __name__ == '__main__':
    do_file("text.txt")

text.txt:

# this is comment line.
age = 18  # comment in line
msg1 = "I'm #1."  # comment. there's a # in code.
msg2 = 'you are #2. ' + 'He is #3'  # strange sign ' # ' in comment. 
print('Waiting your answer')

Output:

age = 18  

msg1 = "I'm #1."  

msg2 = 'you are #2. ' + 'He is #3'  

print('Waiting your answer')

Input:

msg1 = "I'm #1."  # comment. there's a # in code.  the regex#.*$ will match #1."  # comment. there's a # in code. . Right match shoud be # comment. there's a # in code.

Output:

msg1 = "I'm #1."  
Pygirl
  • 12,969
  • 5
  • 30
  • 43