Rimuovi i commenti a riga singola e multilinea dalla stringa


19

Obbiettivo

Usando il linguaggio di programmazione che preferisci, scrivi il programma più breve per eliminare i commenti da una stringa che rappresenta un programma C.


Ingresso

La stringa può essere considerata come qualsiasi forma di input, ma può anche essere considerata come variabile.


Istruzioni

Devono essere rimossi due diversi tipi di commenti:

  • commenti multilinea , che iniziano /*e finiscono con*/
  • commenti a riga singola , che iniziano //e terminano con interruzioni di riga in stile Linux (LF, \n)

I commenti nelle stringhe non devono essere eliminati. Ai fini di questa sfida, devi solo considerare "le stringhe delimitate. In particolare, è possibile ignorare la possibilità di 'letterali di caratteri delimitati. Puoi anche ignorare le trigrafi e le continuazioni di linea ( /\<LF>*...).


Esempi

Ingresso:

#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;
}

Produzione:

#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;
}

Ingresso:

/*
    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.*/

Produzione:

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

    int butNotThis = 42;

    int bar = 4 * 3; 
    return 0;
}

1
Da dove è printf("\"/* This will stay too */\"\n");apparso nel dovrebbe diventare codice?
arte

Oops, scusa ... era solo un errore di battitura. Grazie per averlo notato!
Mathieu Rodic,

Gli spazi bianchi contano? Ci sono 4 spazi davanti ai // this comment will be removedquali è appena scomparso. Qualche regola per quello?
arte

1
Non conosco bene nessuna delle lingue elencate, quindi una specie di specifica autonoma sarebbe gradita, insieme ad altri esempi.
Zgarb,

@manatwork: la rimozione degli spazi bianchi non è obbligatoria
Mathieu Rodic

Risposte:


11

Retina , 35 + 1 + 2 = 38 byte

Questo programma è composto da due file, quindi ho incluso una penalità di 1 byte per il secondo file .

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

Questa è una semplice sostituzione regex, usando il sapore .NET (sebbene funzionerebbe allo stesso modo nella maggior parte degli altri gusti).

L'idea è quella di abbinare sia i commenti che le stringhe, ma riscrivere la corrispondenza solo se fosse una stringa. Abbinando esplicitamente le stringhe, vengono saltate durante la ricerca di commenti.


1
Questo funziona sorprendentemente bene in PHP: regex101.com/r/kB5kA4/1
Ismael Miguel

1
@IsmaelMiguel Sì, non ho usato nulla di specifico. L'unico motivo per cui ho scelto .NET è perché Retina mi permette di scrivere programmi solo regex senza alcun sovraccarico di chiamare qualcosa del genere preg_replace.
Martin Ender,

Ne sono consapevole. L'hai usato parecchio prima. Se ho ragione, è stato creato da te. Era per i curiosi. Inoltre, ora disponi di una suite di test in cui puoi testare qualsiasi cambiamento si presenti in questa domanda (ne prevedo molti)
Ismael Miguel

Bello! Questa espressione regolare funziona anche con altri linguaggi di programmazione (quando si sfuggono le barre).
Mathieu Rodic,

Ho usato la tua tecnica regex per migliorare una libreria di terze parti con cui lavoro: Dojo Toolkit
mbomb007

15

Shell + coreutils + collezione di compilatori gcc, 31 byte

Questa risposta può sembrare un po 'di scappatoia, ma non ho visto nulla di specificamente vietarlo nella domanda.

Invece di usare espressioni regolari goffe, perché non usare lo strumento che è stato creato per il lavoro. Non dovrebbe avere problemi a dare risultati corretti:

cpp -fpreprocessed -o- -|sed 1d

Riceve input da STDIN e output su STDOUT. Normalmente ccpeseguirà tutta la preelaborazione (file di intestazione, espansione macro, rimozione commenti, ecc.), Ma con l' -fpreprocessedopzione salterà la maggior parte dei passaggi, ma rimuoverà comunque i commenti. Inoltre, cpp aggiunge una riga simile # 1 "<stdin>"all'inizio dell'output, quindi sedè lì per eliminarlo.


1
"-fpreprocessed è implicita se il file di input ha una delle estensioni .i, .iio .mi". potresti essere in grado di salvare alcuni byte salvando il file in qualcosa di simile a.iinvece di usare il flag?
Martin Ender,

@ MartinBüttner Sì, l'ho notato anche nel manuale. Quindi mi aspetto che qualcosa di simile cat>i.i;cpp -o- i.i|sed 1dsia equivalente. Ne consegue che la preelaborazione completa (ad esempio, sono inseriti i contenuti completi di stdio.h). Possibile bug gcc ??? Beh, forse controllerò la fonte cpp quando avrò un mo '.
Trauma digitale

È possibile rimuovere |sed 1dl' -Popzione se si aggiunge l' opzione. Si noti che (come consentito dalla domanda), poiché prevede codice pre-elaborato, non gestirà correttamente le trigrafi o le continuazioni di riga.
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 byte

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

Come puoi vedere qui , la regex è composta da 2 gruppi di acquisizione alternati. Il primo cattura tutte le stringhe tra virgolette. Il secondo tutti i commenti.

Tutto ciò che dobbiamo fare è rimuovere tutto ciò che è stato catturato dal 2 ° gruppo.

Esempio:

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 + alcune annotazioni:

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

Conversione della risposta di @Martin Ender per php:

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

ora $strha perso commenti a riga singola e multipla. Ciò è utile per rimuovere i commenti nei dati JSON prima di alimentare json_decode().


Forse potresti ridurre il conteggio dei byte usando un operatore ternario?
Mathieu Rodic,

0

C # (262 caratteri):

Da questa ottima risposta SO :

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);

-1

JS (ES6), 47 caratteri (pulire)

DEMO: http://codepen.io/anon/pen/dPEMro

a=b=>b.replace(/(\/\*[^]*?\*\/|\/\/.*)\n?/g,"")

Ispirato dai miei minificatori codegolfati: http://xem.github.io/miniMinifier/

non gestisce ancora i commenti nelle stringhe ...

Sono curioso di vedere se è possibile ottenere questo risultato nelle regex di JS.


Se questa risposta non soddisfa i requisiti, deve essere riparata o eliminata.
mbomb007,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.