Eliminar comentarios de una sola línea y de varias líneas de la cadena

19

Objetivo

Usando el lenguaje de programación de su elección, escriba el programa más corto para eliminar los comentarios de una cadena que representa un programa en C.


Entrada

La cadena se puede tomar como cualquier forma de entrada, pero también se puede tomar como una variable.


Instrucciones

Se deben eliminar dos tipos diferentes de comentarios:

  • comentarios multilínea , comenzando /*y terminando con*/
  • comentarios de una sola línea , comenzando //y terminando con saltos de línea estilo Linux (LF, \n)

Los comentarios dentro de las cadenas no se deben eliminar. Para el propósito de este desafío, solo necesita considerar "cadenas delimitadas. En particular, puede ignorar la posibilidad de 'literales de caracteres delimitados. También puede ignorar los trigrafos y las continuaciones de línea ( /\<LF>*...).


Ejemplos

Entrada:

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

Salida:

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

Entrada:

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

Salida:

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

    int butNotThis = 42;

    int bar = 4 * 3; 
    return 0;
}
Mathieu Rodic
fuente
1
¿De dónde printf("\"/* This will stay too */\"\n");apareció eso en el debería convertirse en código?
manatwork el
Oops, lo siento ... fue solo un error tipográfico. ¡Gracias por notarlo!
Mathieu Rodic
¿Cuentan los espacios en blanco? Hay 4 espacios delante de los // this comment will be removedcuales simplemente desaparecieron. ¿Alguna regla para eso?
manatwork 01 de
1
No conozco bien ninguno de los idiomas enumerados, por lo que sería bueno contar con algún tipo de especificación autónoma, junto con más ejemplos.
Zgarb 01 de
@manatwork: la eliminación de espacios en blanco no es obligatoria
Mathieu Rodic

Respuestas:

11

Retina , 35 + 1 + 2 = 38 bytes

Este programa consta de dos archivos, por lo tanto, he incluido una penalización de 1 byte para el segundo archivo .

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

Este es un reemplazo simple de expresiones regulares, usando el sabor .NET (aunque esto funcionaría igual en la mayoría de los otros sabores).

La idea es hacer coincidir los comentarios y las cadenas, pero solo escribir la coincidencia de nuevo si era una cadena. Al hacer coincidir las cadenas explícitamente, se omiten al buscar comentarios.

Martin Ender
fuente
1
Esto funciona sorprendentemente bien en PHP: regex101.com/r/kB5kA4/1
Ismael Miguel
1
@IsmaelMiguel Sí, no utilicé nada específico de la función. La única razón por la que elegí .NET es porque Retina me permite escribir programas solo de expresiones regulares sin ninguna sobrecarga de llamar a algo así preg_replace.
Martin Ender
Estoy al tanto. Lo has usado bastante antes. Si estoy en lo cierto, fue creado por ti. Fue para los curiosos. Y también, ahora tiene un conjunto de pruebas donde puede probar cualquier cambio que surja en esta pregunta (predigo muchos)
Ismael Miguel
¡Agradable! Esta expresión regular incluso funciona con otros lenguajes de programación (cuando se escapan las barras).
Mathieu Rodic
Utilicé tu técnica de expresiones regulares para mejorar una biblioteca de terceros con la que trabajo: Dojo Toolkit
mbomb007
15

Colección del compilador Shell + coreutils + gcc, 31 bytes

Esta respuesta puede parecer un poco falsa, pero no vi nada que la prohibiera específicamente en la pregunta.

En lugar de usar expresiones regulares torpes, ¿por qué no usar la herramienta que se creó para el trabajo? No debería tener problemas para dar resultados correctos:

cpp -fpreprocessed -o- -|sed 1d

Toma la entrada de STDIN y la salida a STDOUT. Normalmente ccphará todo el preprocesamiento (archivos de encabezado, expansión de macros, eliminación de comentarios, etc.), pero con la -fpreprocessedopción, omitirá la mayoría de los pasos, pero aún eliminará los comentarios. Además, cpp agrega una línea como # 1 "<stdin>"al comienzo de la salida, por lo que sedestá allí para eliminarla.

Trauma digital
fuente
1
"-fpreprocessed es implícito si el archivo de entrada tiene una de las extensiones .i, .iio .mi". ¿podría guardar algunos bytes guardando el archivo en algo así como en a.ilugar de usar la bandera?
Martin Ender
@ MartinBüttner Sí, también lo noté en el manual. Entonces esperaría que algo así cat>i.i;cpp -o- i.i|sed 1dfuera equivalente. Pero se produce un preprocesamiento completo (por ejemplo, se inserta el contenido completo de stdio.h). Posible error de gcc ??? Bueno, tal vez verifique la fuente de cpp cuando tenga un mo '.
Trauma digital
Puede eliminar el |sed 1dsi agrega la -Popción. Tenga en cuenta que (según lo permitido por la pregunta), ya que espera código preprocesado, no manejará los trigrafos o las continuaciones de línea correctamente.
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;}}

Sin golf

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;
}
Ilya Gazman
fuente
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

Como puede ver aquí , la expresión regular consta de 2 grupos de captura alternativos. El primero captura todas las cadenas citadas. El segundo todos los comentarios.

Todo lo que necesitamos hacer es eliminar todo lo capturado por el segundo grupo.

Ejemplo:

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;
}
pepp
fuente
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 + algunas anotaciones:

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
]
draegtun
fuente
1

PHP

Convirtiendo la respuesta de @Martin Ender para php:

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

ahora $strha perdido comentarios de una o varias líneas. Esto es útil para eliminar comentarios en datos JSON antes de alimentarlos json_decode().

centurias
fuente
¿Quizás podría reducir el recuento de bytes utilizando un operador ternario?
Mathieu Rodic
0

C # (262 caracteres):

De esta muy buena respuesta 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);
vrluckyin
fuente
-1

JS (ES6), 47 caracteres (wip)

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

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

Inspirado por mis minificadores codegolfed: http://xem.github.io/miniMinifier/

no maneja comentarios en cadenas todavía ...

Tengo curiosidad por ver si es posible lograr eso en JS regexes.

xem
fuente
Si esta respuesta no cumple con los requisitos, debe ser reparada o eliminada.
mbomb007