Entfernen Sie einzeilige und mehrzeilige Kommentare aus der Zeichenfolge


19

Tor

Schreiben Sie in der Programmiersprache Ihrer Wahl das kürzeste Programm , um Kommentare aus einer Zeichenfolge zu entfernen, die ein C-Programm darstellt.


Eingang

Die Zeichenfolge kann als eine beliebige Form der Eingabe verwendet werden, sie kann jedoch auch als Variable verwendet werden.


Anleitung

Zwei verschiedene Arten von Kommentaren sind zu entfernen:

  • Mehrzeilige Kommentare , beginnend mit /*und endend mit*/
  • Einzeilige Kommentare , beginnend mit //und endend mit Zeilenumbrüchen im Linux-Stil (LF, \n)

Kommentare in Strings dürfen nicht gelöscht werden. Für diese Herausforderung müssen Sie nur "-begrenzte Zeichenfolgen berücksichtigen . Insbesondere können Sie die Möglichkeit von 'Literalen mit -begrenzten Zeichen ignorieren . Sie können auch Trigraphen und Linienfortsetzungen ignorieren ( /\<LF>*...).


Beispiele

Eingang:

#include <stdio.h>

int main(int argc, char** argv)
{
    // this comment will be removed
    if (argc > 1) {
        printf("Too many arguments.\n");   // this too will be removed
        return 1;
    }
    printf("Please vist http://this.will.not.be.removed.com\n");
    printf("/* This will stay */\n");
    printf("\"/* This will stay too */\"\n");
    printf("//and so will this\\");
    // but not this
    printf("just \"ano//ther\" test.");
    return 0;
}

Ausgabe:

#include <stdio.h>

int main(int argc, char** argv)
{

    if (argc > 1) {
        printf("Too many arguments.\n");   
        return 1;
    }
    printf("Please vist http://this.will.not.be.removed.com\n");
    printf("/* This will stay */\n");
    printf("\"/* This will stay too */\"\n");
    printf("//and so will this\\");

    printf("just \"ano//ther\" test.");
    return 0;
}

Eingang:

/*
    this shall disappear
*/
#include <string>
int main(int argc, char** argv)
{
    string foo = ""/*remove that!**/;
    // Remove /* this
    int butNotThis = 42;
    // But do */ remove this
    int bar = 4 /*remove this*/* 3; // but don't remove that 3. */
    return 0;//just a comment
}/*end of the file has been reached.*/

Ausgabe:

#include <string>
int main(int argc, char** argv)
{
    string foo = "";

    int butNotThis = 42;

    int bar = 4 * 3; 
    return 0;
}

1
Von dort , wo das printf("\"/* This will stay too */\"\n");erschien in der werden soll Code?
Handarbeit

Ups, sorry ... es war nur ein Tippfehler. Danke fürs bemerken!
Mathieu Rodic

Zählen Leerzeichen? Es gibt 4 Felder, vor // this comment will be removeddenen gerade verschwunden ist. Irgendeine Regel dafür?
Handarbeit

1
Ich kenne keine der aufgelisteten Sprachen so gut, daher wäre eine Art eigenständige Spezifikation zusammen mit weiteren Beispielen nett.
Zgarb

@ Manatwork: Leerzeichen entfernen ist nicht obligatorisch
Mathieu Rodic

Antworten:


11

Retina , 35 + 1 + 2 = 38 Bytes

Dieses Programm besteht aus zwei Dateien, daher habe ich eine 1-Byte-Strafe für die zweite Datei eingefügt .

//.*|/\*[\s\S]*?\*/|("(\\.|[^"])*")
$1

Dies ist ein einfacher regulärer Ausdruck, der die .NET-Variante verwendet (obwohl dies in den meisten anderen Varianten genauso funktioniert).

Die Idee ist, sowohl Kommentare als auch Zeichenfolgen abzugleichen, aber die Übereinstimmung nur dann zurückzuschreiben, wenn es sich um eine Zeichenfolge handelte. Wenn die Zeichenfolgen explizit abgeglichen werden, werden sie bei der Suche nach Kommentaren übersprungen.


1
Dies funktioniert überraschend gut in PHP: regex101.com/r/kB5kA4/1
Ismael Miguel

1
@IsmaelMiguel Ja, ich habe keine spezifischen Funktionen verwendet. Der einzige Grund, warum ich mich für .NET entschieden habe, ist, dass ich mit Retina regex-reine Programme schreiben kann, ohne dass der Aufwand für Aufrufe wie z preg_replace.
Martin Ender

Das ist mir bewusst. Sie haben es schon oft benutzt. Wenn ich richtig bin, wurde es von Ihnen erstellt. Es war für die Neugierigen. Außerdem haben Sie jetzt eine Testsuite, in der Sie testen können, welche Änderungen in dieser Frage auftreten (ich sage viele voraus)
Ismael Miguel

Nett! Dieser reguläre Ausdruck funktioniert sogar mit anderen Programmiersprachen (wenn Schrägstriche maskiert werden).
Mathieu Rodic

Ich habe Ihre Regex-Technik verwendet, um eine Drittanbieter-Bibliothek zu verbessern, mit der ich arbeite: Dojo Toolkit
mbomb007

15

Shell + Coreutils + Gcc-Compiler-Auflistung, 31 Bytes

Diese Antwort mag ein bisschen lückenhaft erscheinen, aber ich habe in der Frage nichts spezielles gesehen, was sie verbietet.

Verwenden Sie nicht umständliche reguläre Ausdrücke, sondern das für den Job erstellte Tool. Es sollte kein Problem geben korrekte Ergebnisse:

cpp -fpreprocessed -o- -|sed 1d

Übernimmt die Eingabe von STDIN und gibt sie an STDOUT aus. Normalerweise ccpwird die gesamte Vorverarbeitung durchgeführt (Header-Dateien, Makro-Erweiterung, Entfernen von Kommentaren usw.), aber mit der -fpreprocessedOption werden die meisten Schritte übersprungen, aber es werden weiterhin Kommentare entfernt. Außerdem fügt cpp eine Zeile wie # 1 "<stdin>"am Anfang der Ausgabe hinzu, damit seddiese gelöscht werden kann.


1
msgstr "- fpreprocessed ist implizit, wenn die Eingabedatei eine der Erweiterungen hat .i, .iioder .mi". könnten Sie in der Lage sein, einige Bytes zu speichern, indem Sie die Datei in etwas speichern, a.ianstatt das Flag zu verwenden?
Martin Ender

@ MartinBüttner Ja, das ist mir auch im Handbuch aufgefallen. Ich würde also erwarten, dass etwas cat>i.i;cpp -o- i.i|sed 1dgleichwertig ist. Es erfolgt jedoch eine vollständige Vorverarbeitung (z. B. wird der gesamte Inhalt von stdio.h eingefügt). Möglicher gcc Bug ??? Naja, vielleicht überprüfe ich die cpp-Quelle, wenn ich einen mo 'bekomme.
Digital Trauma

Sie können das entfernen, |sed 1dwenn Sie die -POption hinzufügen . Beachten Sie, dass (wie in der Frage angegeben) vorverarbeiteter Code nicht ordnungsgemäß mit Trigraphen oder Linienfortsetzungen verarbeitet werden kann.
sch

3

Java 365

String a(String s){String o="";int m=1;for(int i=0;i<s.length();i++){String u=s.substring(i,Math.min(i+2,s.length()));char c=s.charAt(i);switch(m){case 1:m=u.equals("/*")?5:u.equals("//")?4:c=='"'?3:1;break;case 3:m=c=='"'?1:c=='\\'?2:3;break;case 2:m=3;break;case 4:m=c=='\n'?1:4;continue;case 5:m=u.equals("*/")?1:5;i+=m==1?1:0;continue;}o+=m<4?c:"";}return o;}}

Ungolfed

public static final int DEFAULT = 1;
public static final int ESCAPE = 2;
public static final int STRING = 3;
public static final int ONE_LINE_COMMENT = 4;
public static final int MULTI_LINE_COMMENT = 5;

String clear(String s) {
    String out = "";
    int mod = DEFAULT;
    for (int i = 0; i < s.length(); i++) {
        String substring = s.substring(i, Math.min(i + 2 , s.length()));
        char c = s.charAt(i);
        switch (mod) {
            case DEFAULT: // default
                mod = substring.equals("/*") ? MULTI_LINE_COMMENT : substring.equals("//") ? ONE_LINE_COMMENT : c == '"' ? STRING : DEFAULT;
                break;
            case STRING: // string
                mod = c == '"' ? DEFAULT : c == '\\' ? ESCAPE : STRING;
                break;
            case ESCAPE: // string
                mod = STRING;
                break;
            case ONE_LINE_COMMENT: // one line comment
                mod = c == '\n' ? DEFAULT : ONE_LINE_COMMENT;
                continue;
            case MULTI_LINE_COMMENT: // multi line comment
                mod = substring.equals("*/") ? DEFAULT : MULTI_LINE_COMMENT;
                i += mod == DEFAULT ? 1 : 0;
                continue;
        }
        out += mod < 4 ? c : "";
    }

    return out;
}

2

Python2 - 163 134 Bytes

import re
def f(s):
 for x in re.findall(r'("[^\n]*"(?!\\))|(//[^\n]*$|/(?!\\)\*[\s\S]*?\*(?!\\)/)',s,8):s=s.replace(x[1],'')
 print s

Wie Sie hier sehen können , besteht der Regex aus 2 abwechselnden Erfassungsgruppen. Der erste erfasst alle angegebenen Zeichenfolgen. Der zweite alle Kommentare.

Alles, was wir tun müssen, ist, alles zu entfernen, was von der 2. Gruppe erfasst wurde.

Beispiel:

Python 2.7.9 (default, Dec 11 2014, 04:42:00) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> def f(s):
...  for x in re.findall(r'("[^\n]*"(?!\\))|(//[^\n]*$|/(?!\\)\*[\s\S]*?\*(?!\\)/)',s,8):s=s.replace(x[1],'')
...  print s
... 
>>> code = r'''#include <stdio.h>
... 
... int main(int argc, char** argv)
... {
...     // this comment will be removed
...     if (argc > 1) {
...         printf("Too many arguments.\n");   // this too will be removed
...         return 1;
...     }
...     printf("Please vist http://this.will.not.be.removed.com\n");
...     printf("/* This will stay */\n");
...     printf("\"/* This will stay too */\"\n");
...     printf("//and so will this\\");
...     // but not this
...     printf("just \"ano//ther\" test.");
...     return 0;
... }
... /*
...     this shall disappear
... */
... #include <string>
... int main(int argc, char** argv)
... {
...     string foo = ""/*remove that!**/;
...     // Remove /* this
...     int butNotThis = 42;
...     // But do */ remove this
...     int bar = 4 /*remove this*/* 3; // but don't remove that 3. */
...     return 0;//just a comment
... }/*end of the file has been reached.*/'''
>>> f(code)
#include <stdio.h>

int main(int argc, char** argv)
{

    if (argc > 1) {
        printf("Too many arguments.\n");   
        return 1;
    }
    printf("Please vist http://this.will.not.be.removed.com\n");
    printf("/* This will stay */\n");
    printf("\"/* This will stay too */\"\n");
    printf("//and so will this\\");

    printf("just \"ano//ther\" test.");
    return 0;
}

#include <string>
int main(int argc, char** argv)
{
    string foo = "";

    int butNotThis = 42;

    int bar = 4 * 3; 
    return 0;
}

1

Rebol - 151

f: func[t][Q:{"}W: complement charset Q parse t[any[[Q any["\\"|"\"Q | W]Q]|[a:[["//"to[lf | end]]|["/*"thru"*/"]]b:(remove/part a b):a skip]| skip]]t]

Ungolfed + einige Anmerkungen:

f: func [t] [
    Q: {"}
    W: complement charset Q     ;; any char thats not a double quote

    ; rule to parse t (c program) - it can be ANY of 
    ;     1. string 
    ;     2. OR comment (if so then remove)
    ;     3. OR pass thru

    parse t [
        any [
            ;; 1. String rule
            [Q any ["\\" | "\" Q | W] Q]

            ;; 2. OR comments rule
            | [
                a:  ;; mark beginning of match
                [
                    ;;    // comment    OR  /* comment */
                    ["//" to [lf | end]] | ["/*" thru "*/"]
                ]
                b:  ;; mark end of match 
                (remove/part a b) :a skip   ;; remove comment
            ]

            ;; 3. OR allow thru (so not a String or Comment)
            | skip
        ]
    ]

    t
]

1

PHP

@Martin Enders Antwort für PHP konvertieren:

$str = preg_replace_callback('/\/\/.*|\/\*[\s\S]*?\*\/|("(\\.|[^"])*")/m', 
  function($matches){
     if(\is_array($matches) && (\count($matches) > 1)){
        return $matches[1];
     }else{
        return '';
     }
  }, $str);

hat jetzt $strein- und mehrzeilige Kommentare verloren. Dies ist nützlich, um Kommentare in JSON-Daten zu entfernen, bevor sie an gesendet werden json_decode().


Vielleicht könnten Sie die Anzahl der Bytes mithilfe eines ternären Operators reduzieren?
Mathieu Rodic

0

C # (262 Zeichen):

Aus dieser sehr guten SO Antwort:

string a(string i){return Regex.Replace(i, @"/\*(.*?)\*/|//(.*?)\r?\n|""((\\[^\n]|[^""\n])*)""|@(""[^""]*"")+", m => { var v = m.Value; if (v.StartsWith("/*") || v.StartsWith("//")) return v.StartsWith("//") ? "\r\n" : ""; return v; }, RegexOptions.Singleline);

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.