Frage

Ich suche Python-Code, C und C ++ Kommentare aus einem String entfernt. (Nehmen Sie die Zeichenfolge enthält eine komplette C-Quelldatei.)

Ich weiß, dass ich mit einem Regex .match () Teil könnte, aber das löst nicht Verschachtelung /* oder ein // in einem /* */ hat.

Im Idealfall würde ich eine nicht-naive Implementierung bevorzugen, die richtig peinliche Fälle behandelt.

War es hilfreich?

Lösung

Ich weiß nicht, ob Sie mit sed vertraut sind, die UNIX-basierte (aber Windows erhältlich) Textanalyse-Programm, aber ich habe einen Sed-Skript hier die C / C ++ Kommentare aus einer Datei entfernen. Es ist sehr klug; zum Beispiel, wird es ‚//‘ und ‚/ *‘ gefunden ignorieren, wenn in einer String-Erklärung, etc. Innerhalb Pythons, kann es mit dem folgenden Code verwendet werden:

import subprocess
from cStringIO import StringIO

input = StringIO(source_code) # source_code is a string with the source code.
output = StringIO()

process = subprocess.Popen(['sed', '/path/to/remccoms3.sed'],
    input=input, output=output)
return_code = process.wait()

stripped_code = output.getvalue()

In diesem Programm sind source_code die Variablen, die den C / C ++ Quellcode zu halten, und schließlich stripped_code wird C / C ++ Code mit den entfernt Kommentaren halten. Natürlich, wenn Sie die Datei auf der Festplatte haben, könnten Sie die input und output haben Variablen auf diese Dateien (input im Lesemodus, output im Schreibmodus) zeigt Dateihandles sein. remccoms3.sed ist die Datei aus dem obigen Link, und es sollte in einem lesbaren Speicherort auf dem Datenträger gespeichert werden. sed ist auch auf Windows und kommt standardmäßig auf den meisten GNU / Linux-Distributionen und Mac OS X.

installiert

Dies wird wahrscheinlich besser als eine reine Python-Lösung; keine Notwendigkeit, das Rad neu zu erfinden.

Andere Tipps

Diese Griffe C ++ -. Stil Kommentare, C-Stil Kommentare, Streicher und einfache Verschachtelung davon

def comment_remover(text):
    def replacer(match):
        s = match.group(0)
        if s.startswith('/'):
            return " " # note: a space and not an empty string
        else:
            return s
    pattern = re.compile(
        r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
        re.DOTALL | re.MULTILINE
    )
    return re.sub(pattern, replacer, text)

Strings muss aufgenommen werden, weil Kommentar-Marker in ihnen keinen Kommentar starten.

Edit:. re.sub keine Fahnen nehmen hat, so hatte zuerst das Muster zu kompilieren

Edit2:. Hinzugefügt Zeichenliterale, da sie Anführungszeichen enthalten könnte, die sonst als String-Trennzeichen erkannt werden würde

Edit3:. , um den Fall behoben, bei dem ein juristischer Ausdruck int/**/x=5; intx=5; werden würde, die nicht kompiliert werden würde, durch den Kommentar mit einem Leerzeichen ersetzen eher dann eine leere Zeichenfolge

C (und C ++) Kommentare können nicht geschachtelt werden. Reguläre Ausdrücke funktionieren gut:

//.*?\n|/\*.*?\*/

Dies erfordert die „Single line“ Flag (Re.S), weil ein C Kommentar kann mehrere Zeilen umfassen.

def stripcomments(text):
    return re.sub('//.*?\n|/\*.*?\*/', '', text, flags=re.S)

sollten Dieser Code arbeiten.

/ EDIT: Beachten Sie, dass mein obiger Code tatsächlich eine Annahme über Zeilenende macht! Dieser Code wird nicht funktionieren auf einer Mac-Textdatei. Dies kann jedoch relativ leicht geändert werden:

//.*?(\r\n?|\n)|/\*.*?\*/

Dieser reguläre Ausdruck sollte auf allen Textdateien arbeitet, unabhängig von ihren Zeilenenden (deckt Windows, Unix und Mac-Zeilenenden).

/ EDIT: MizardX und Brian (in den Kommentaren) eine gültige Bemerkung über den Umgang mit Saiten. Ich habe ganz vergessen darüber, weil die oben regex von einem Parsing-Modul gezupft wird, die für Strings zusätzliche Handhabung hat. MizardX-Lösung sollte sehr gut funktionieren, aber es behandelt nur Strings in doppelten Anführungszeichen.

Vergessen Sie nicht, dass in C, Backslash-Newline eliminiert wird, bevor Kommentare verarbeitet werden, und trigraphs werden, bevor das verarbeitet (da ?? / die trigraph für Backslash). Ich habe ein C-Programm namens SCC (Streifen C / C ++ Kommentare) und hier ist ein Teil des Testcodes ...

" */ /* SCC has been trained to know about strings /* */ */"!
"\"Double quotes embedded in strings, \\\" too\'!"
"And \
newlines in them"

"And escaped double quotes at the end of a string\""

aa '\\
n' OK
aa "\""
aa "\
\n"

This is followed by C++/C99 comment number 1.
// C++/C99 comment with \
continuation character \
on three source lines (this should not be seen with the -C fla
The C++/C99 comment number 1 has finished.

This is followed by C++/C99 comment number 2.
/\
/\
C++/C99 comment (this should not be seen with the -C flag)
The C++/C99 comment number 2 has finished.

This is followed by regular C comment number 1.
/\
*\
Regular
comment
*\
/
The regular C comment number 1 has finished.

/\
\/ This is not a C++/C99 comment!

This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.

/\
\* This is not a C or C++  comment!

This is followed by regular C comment number 2.
/\
*/ This is a regular C comment *\
but this is just a routine continuation *\
and that was not the end either - but this is *\
\
/
The regular C comment number 2 has finished.

This is followed by regular C comment number 3.
/\
\
\
\
* C comment */

Dies gilt nicht illustrieren trigraphs. Beachten Sie, dass Sie mehrere Schrägstriche am Ende einer Zeile, aber die Linie Spleißen Macht kümmert sich nicht darum, wie viele es sind, aber die nachfolgende Verarbeitung haben kann. Schreiben usw. eine einzelne Regex all diese Fälle zu behandeln, wird nicht-triviale (aber das ist anders als unmöglich).

Dieser Beitrag stellt eine codierte-out-Version der Verbesserung Markus Jarderot den Code, der von atikat beschrieben wurde, in einem Kommentar zu Markus Jarderot der Buchung. (Dank an beide für den ursprünglichen Code bereitstellt, die mir eine Menge Arbeit erspart.)

Um die Verbesserung etwas ausführlicher zu beschreiben: Die Verbesserung hält die Zeilennummerierung intakt. (Dies geschieht, indem Sie die Zeilenumbrüche intakt in die Saiten zu halten, durch die die C / C ++ Kommentare ersetzt werden.)

Diese Version des C / C ++ Kommentar Entfernungsfunktion ist geeignet, wenn Sie Fehlermeldungen an die Benutzer generieren möchten (z Parsing-Fehler), die Zeilennummern enthalten (das heißt Zeilennummern gültig für den ursprünglichen Text).

import re

def removeCCppComment( text ) :

    def blotOutNonNewlines( strIn ) :  # Return a string containing only the newline chars contained in strIn
        return "" + ("\n" * strIn.count('\n'))

    def replacer( match ) :
        s = match.group(0)
        if s.startswith('/'):  # Matched string is //...EOL or /*...*/  ==> Blot out all non-newline chars
            return blotOutNonNewlines(s)
        else:                  # Matched string is '...' or "..."  ==> Keep unchanged
            return s

    pattern = re.compile(
        r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
        re.DOTALL | re.MULTILINE
    )

    return re.sub(pattern, replacer, text)

Die reguläre Ausdruck Fälle werden in einigen Situationen fallen nach unten, wie in dem eine Zeichenfolge, die eine Subsequenz wörtliche enthält, die den Kommentar Syntax entspricht. Man braucht wirklich einen Parse-Baum damit zu umgehen.

können Sie in der Lage sein, py ++ die C ++ Quelle zu analysieren mit GCC.

  

Py ++ neu zu erfinden das Rad nicht. Es   verwendet GCC C ++ Kompilierer C ++ parsen   Quelldaten. Um genauer zu sein, die   Werkzeugkette sieht wie folgt aus:

     

Quellcode wird auf GCC-XML übergeben   GCC-XML übergibt sie an GCC C ++ Compiler   GCC-XML erzeugt eine XML-Beschreibung   ein C ++ Programm von GCC internen   Darstellung. Py ++ verwendet pygccxml   Paket zu lesen GCC-XML erzeugt   Datei. Unterm Strich - man kann sein   sicher, dass alle Ihre Erklärungen sind   richtig gelesen.

oder, vielleicht auch nicht. unabhängig, das ist keine triviale Parse.

@ RE-basierte Lösungen - Sie werden kaum einen RE finden, die alle möglichen ‚ungeschickt‘ Fälle korrekt behandelt, es sei denn, Sie Eingabe einschränken (z keine Makros). für eine kugelsichere Lösung, Sie haben wirklich keine andere Wahl, als die wirkliche Grammatik nutzen.

Es tut mir leid dies nicht eine Python-Lösung, aber man könnte auch ein Tool, das es versteht, Kommentare zu entfernen, wie Sie Ihre C / C ++ Präprozessor. Hier ist, wie GNU CPP tut es .

cpp -fpreprocessed foo.c

Es gibt auch eine nicht-Python Antwort: das Programm verwenden, stripcmt :

  

StripCmt ist ein einfaches Dienstprogramm geschrieben   in C entfernen Kommentare von C, C ++,   und Java-Quelldateien. In der großen   Tradition von Unix-Textverarbeitung   Programme, kann es entweder als Funktion   FIFO (First In - First Out) Filter oder   akzeptieren Argumente auf der Kommandozeile.

Die für mich folgende gearbeitet:

from subprocess import check_output

class Util:
  def strip_comments(self,source_code):
    process = check_output(['cpp', '-fpreprocessed', source_code],shell=False)
    return process 

if __name__ == "__main__":
  util = Util()
  print util.strip_comments("somefile.ext")

Dies ist eine Kombination aus dem subprocess und dem CPP-Präprozessor. Für mein Projekt habe ich eine Utility-Klasse namens „Tool“, das ich verschiedene Werkzeuge halten ich / müssen.

Sie brauchen nicht wirklich einen Parse-Baum dies perfekt zu tun, aber Sie tun, in der Tat müssen die Token-Strom entspricht dem, was durch den Compiler-Frontend erzeugt wird. Ein solcher Token Strom muss necessarilyy kümmern sich um alle die Seltsamkeit wie Line-Fortsetzung Kommentar Start, den Kommentar in string, trigraph Normalisierung beginnen, etc. Wenn Sie die Token-Strom haben, löschen Sie die Kommentare einfach. (Ich habe ein Tool, das genau solche Token-Streams erzeugt, wie, erraten, was das vordere Ende eines echten Parser, der einen echten Parse-Baum :) erzeugt.

Die Tatsache, dass die Zeichen einzeln von regulären Ausdrücken erkannt werden deutet darauf hin, dass Sie im Prinzip einen regulären Ausdruck schreiben, dass der Kommentar Lexeme herausgreifen wird. Die eigentliche Komplexität der Satz von regulären Ausdrücken für die tokenizer (zumindest die, die wir geschrieben haben) schlägt vor, Sie dies in der Praxis nicht möglich ist; sie einzeln zu schreiben war schwer genug. Wenn Sie es nicht perfekt machen wollen, na ja, dann sind die meisten der RE-Lösungen oben gut.

Warum Sie wollen Streifen Kommentare über mich ist, wenn Sie einen Code obfuscator bauen. In diesem Fall müssen Sie es vollkommen recht haben.

Ich lief vor kurzem über dieses Problem, wenn ich eine Klasse nahm, wo der Professor uns erforderlich javadoc aus unserem Quellcode abzustreifen, bevor er ihn für einen Code Überprüfung eingereicht haben. Wir hatten dies mehrmals zu tun, aber wir konnten nicht nur die javadoc dauerhaft entfernen, weil wir wurden javadoc HTML-Dateien als auch zu generieren. Hier ist ein kleiner Python-Skript Ich habe den Trick zu tun. Da javadoc mit / beginnt ** und endet mit * /, sieht das Skript für diese Token, aber das Skript kann geändert werden, für Ihre Reise. Es behandelt auch einzelne Zeile Block Kommentare und Fälle, in denen ein Block Kommentar endet, aber es ist immer noch nicht-kommentierten Code auf der gleichen Linie wie der Block Kommentar endet. Ich hoffe, das hilft!

WARNUNG: Diese Skripte ändert den Inhalt von Dateien übergeben und speichert sie in den Originaldateien. Es wäre klug, eine Sicherungskopie haben woanders

#!/usr/bin/python
"""
 A simple script to remove block comments of the form /** */ from files
 Use example: ./strip_comments.py *.java
 Author: holdtotherod
 Created: 3/6/11
"""
import sys
import fileinput

for file in sys.argv[1:]:
    inBlockComment = False
    for line in fileinput.input(file, inplace = 1):
        if "/**" in line:
            inBlockComment = True
        if inBlockComment and "*/" in line:
            inBlockComment = False
            # If the */ isn't last, remove through the */
            if line.find("*/") != len(line) - 3:
                line = line[line.find("*/")+2:]
            else:
                continue
        if inBlockComment:
            continue
        sys.stdout.write(line)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top