Usuń komentarze jednowierszowe i wielowierszowe z ciągu

19

Cel

Używając wybranego języka programowania, napisz najkrótszy program, aby wyeliminować komentarze z ciągu znaków reprezentującego program C.


Wejście

Ciąg może być traktowany jako dowolna forma wprowadzania, ale może być również traktowany jako zmienna.


Instrukcje

Należy usunąć dwa różne rodzaje komentarzy:

  • komentarze wielowierszowe , zaczynające się /*i kończące na*/
  • komentarze jednowierszowe , zaczynające się //i kończące na łamaniu wierszy w stylu Linux (LF \n)

Komentarze w ciągach nie mogą być usuwane. Na potrzeby tego wyzwania wystarczy rozważyć "-delimitowane ciągi. W szczególności możesz zignorować możliwość 'literałów znakowych. Możesz także zignorować trygrafy i kontynuacje linii ( /\<LF>*...).


Przykłady

Wejście:

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

Wynik:

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

Wejście:

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

Wynik:

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

    int butNotThis = 42;

    int bar = 4 * 3; 
    return 0;
}
Mathieu Rodic
źródło
1
Skąd to się printf("\"/* This will stay too */\"\n");pojawiło, powinno stać się kodem?
manatwork
Ups, przepraszam ... to była tylko literówka. Dzięki za zauważenie!
Mathieu Rodic
Czy białe znaki się liczą? Przed nim są 4 pola // this comment will be removed. Jakaś reguła?
manatwork
1
Nie znam tak dobrze żadnego z wymienionych języków, więc fajna byłaby jakaś niezależna specyfikacja wraz z większą liczbą przykładów.
Zgarb
@manatwork: usuwanie białych znaków nie jest obowiązkowe
Mathieu Rodic

Odpowiedzi:

11

Siatkówka , 35 + 1 + 2 = 38 bajtów

Ten program składa się z dwóch plików, dlatego do drugiego pliku dołączyłem 1-bajtową karę .

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

Jest to prosta zamiana wyrażenia regularnego przy użyciu smaku .NET (chociaż działałoby to tak samo w większości innych smaków).

Chodzi o to, aby dopasować zarówno komentarze, jak i ciągi, ale zapisz dopasowanie tylko, jeśli był to ciąg. Przez wyraźne dopasowanie ciągów są one pomijane podczas wyszukiwania komentarzy.

Martin Ender
źródło
1
Działa to zaskakująco dobrze w PHP: regex101.com/r/kB5kA4/1
Ismael Miguel
1
@IsmaelMiguel Tak, nie użyłem niczego konkretnego. Jedynym powodem, dla którego wybrałem platformę .NET, jest to, że Retina pozwala mi pisać programy zawierające wyłącznie wyrażenia regularne bez konieczności nazywania czegoś podobnego preg_replace.
Martin Ender,
Jestem tego świadomy. Używałeś go już dość często. Jeśli mam rację, to został stworzony przez ciebie. To było dla ciekawskich. A teraz masz teraz zestaw testów, w którym możesz przetestować wszelkie zmiany, które pojawią się w tym pytaniu (przewiduję wiele)
Ismael Miguel
Ładny! To wyrażenie regularne działa nawet z innymi językami programowania (gdy znaki specjalne są ukrywane).
Mathieu Rodic
Użyłem twojej techniki regex, aby ulepszyć bibliotekę strony trzeciej, z którą współpracuję: Dojo Toolkit
mbomb007
15

Kolekcja kompilatora Shell + coreutils + gcc, 31 bajtów

Ta odpowiedź może wydawać się nieco luźna, ale nie widziałem niczego specjalnie zakazującego jej w pytaniu.

Zamiast używać niezdarnych wyrażeń regularnych, dlaczego nie skorzystać z narzędzia, które zostało zbudowane dla tego zadania. Nie powinno mieć problemu z podaniem poprawnych wyników:

cpp -fpreprocessed -o- -|sed 1d

Pobiera dane wejściowe ze STDIN i dane wyjściowe do STDOUT. Zwykle ccpwykonuje wszystkie wstępne przetwarzanie (pliki nagłówków, rozwijanie makr, usuwanie komentarzy itp.), Ale z tą -fpreprocessedopcją pominie większość kroków, ale nadal usunie komentarze. Ponadto cpp dodaje wiersz podobny # 1 "<stdin>"do początku danych wyjściowych, więc sedistnieje, aby go usunąć.

Cyfrowa trauma
źródło
1
„-fpreprocessed jest niejawna, jeżeli plik wejściowy ma jedną z rozszerzeniami .i, .iilub .mi”. czy możesz zapisać niektóre bajty, zapisując plik w coś podobnego a.izamiast używać flagi?
Martin Ender,
@ MartinBüttner Tak, zauważyłem to również w instrukcji. Spodziewałbym się więc, że coś takiego cat>i.i;cpp -o- i.i|sed 1dbędzie równoważne. Następuje jednak pełne przetwarzanie wstępne (np. Wstawiana jest pełna zawartość pliku stdio.h). Możliwy błąd GCC? Może sprawdzę źródło cpp, kiedy dostanę mo.
Cyfrowa trauma
Możesz usunąć opcję |sed 1ddodania -P. Zwróć uwagę, że (jak pozwala na to pytanie), ponieważ oczekuje na wstępnie przetworzony kod, nie będzie poprawnie obsługiwał kaligrafii ani kontynuacji linii.
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;}}

Nie golfił

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
źródło
2

Python2 - 163 134 bajty

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

Jak widać tutaj , wyrażenie regularne składa się z 2 naprzemiennych grup przechwytywania. Pierwszy przechwytuje wszystkie cytowane ciągi. Drugi wszystkie komentarze.

Wszystko, co musimy zrobić, to usunąć wszystko przechwycone przez 2. grupę.

Przykład:

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;
}
pieprz
źródło
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]

Niegolfowany + kilka adnotacji:

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
źródło
1

PHP

Konwertowanie odpowiedzi Martina Endera na php:

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

teraz $strstracił komentarze jedno- i wieloliniowe. Jest to przydatne do usuwania komentarzy w danych JSON przed karmieniem json_decode().

centurian
źródło
Może mógłbyś zmniejszyć liczbę bajtów używając operatora trójskładnikowego?
Mathieu Rodic
0

C # (262 znaków):

Z tej bardzo dobrej odpowiedzi 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
źródło
-1

JS (ES6), 47 znaków (czyszczenie)

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

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

Zainspirowany moimi kodegolfowymi minifierami: http://xem.github.io/miniMinifier/

nie obsługuje jeszcze komentarzy w ciągach ...

Jestem ciekawy, czy można to osiągnąć w wyrażeniach regularnych JS.

Xem
źródło
Jeśli ta odpowiedź nie spełnia wymagań, należy ją naprawić lub usunąć.
mbomb007