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

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.


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ąć.


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

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

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
]

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().


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.