Видаліть однорядкові та багаторядкові коментарі з рядка


19

Мета

Використовуючи обрану мову програмування, напишіть найкоротшу програму, щоб усунути коментарі з рядка, що представляє програму C.


Вхідні дані

Рядок можна приймати як будь-яку форму введення, але він також може бути прийнятим як змінний.


Інструкції

Два різних коментарі слід видалити:

  • багаторядкові коментарі , починаючи з /*і закінчуючи*/
  • коментарі в одному рядку , починаючи з //і закінчуючи розривами рядків у стилі Linux (LF, \n)

Коментарі в рядках не видаляються. Для цього виклику вам потрібно лише розглянути "рядки з розділеними розмірами. Зокрема, ви можете проігнорувати можливість '-делімітованих символів-літералів. Ви також можете ігнорувати триграфи та продовження рядків ( /\<LF>*...).


Приклади

Вхід:

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

Вихід:

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

Вхід:

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

Вихід:

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

    int butNotThis = 42;

    int bar = 4 * 3; 
    return 0;
}

1
Звідки це printf("\"/* This will stay too */\"\n");з'явилося в коді повинен стати кодом?
манатурка

На жаль, це просто помилка друку. Дякуємо, що помітили!
Матьє Родіч

Чи враховуються пробіли? Перед ними 4 місця, // this comment will be removedщойно зникли. Будь-яке правило для цього?
манатурка

1
Я не знаю жодної із перерахованих мов настільки добре, тож якась автономна специфікація була б непоганою разом із ще кількома прикладами.
Згарб

@manatwork: видалення білого простору не є обов’язковим
Матьє Родік

Відповіді:


11

Сітківка , 35 + 1 + 2 = 38 байт

Ця програма складається з двох файлів, отже, я включив 1-байтове покарання для другого файлу .

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

Це проста заміна регулярного вираження, використовуючи аромат .NET (хоча це діятиме так само в більшості інших ароматів).

Ідея полягає в тому, щоб відповідати як коментарям, так і рядкам, але записувати відповідність лише тоді, якщо це був рядок. При явному зіставленні рядків вони пропускаються під час пошуку коментарів.


1
Це на диво добре працює в PHP: regex101.com/r/kB5kA4/1
Ісмаель Мігель

1
@IsmaelMiguel Так, я не використовував нічого особливого. Єдина причина, яку я вибрав. NET - це те, що Retina дозволяє мені писати програми, призначені лише для регулярних висловлювань, без накладних викликів чогось подібного preg_replace.
Мартін Ендер

Я про це знаю. Ви раніше багато використовували його. Якщо я маю рацію, її створили ви. Це було для допитливих. А також, у вас зараз є тестовий набір, де ви можете перевірити будь-які зміни, що стосуються цього питання (я прогнозую багато)
Ісмаель Мігель

Приємно! Цей регулярний вираз працює навіть з іншими мовами програмування (коли нахиляються косої риски).
Матьє Родіч

Я використав вашу техніку регулярних виразів для вдосконалення бібліотеки третьої сторони, з якою працюю: Dojo Toolkit
mbomb007

15

Колекція компілятора Shell + coreutils + gcc, 31 байт

Ця відповідь може здатися трохи лазівкою, але я нічого не бачив у запитанні.

Замість того, щоб використовувати незграбні регулярні вирази, чому б не використати інструмент, який був побудований для роботи. З правильними результатами не повинно виникнути проблем:

cpp -fpreprocessed -o- -|sed 1d

Приймає вхід з STDIN і виводить на STDOUT. Зазвичай ccpбуде виконано всю попередню обробку (файли заголовків, розширення макросів, видалення коментарів тощо), але з -fpreprocessedможливістю вона пропустить більшість кроків, але все одно видалить коментарі. Крім того, cpp додає рядок, подібний # 1 "<stdin>"до початку виводу, тому sedє можливість його видалити.


1
"-fpreprosedsed є неявним, якщо вхідний файл має одне з розширень .i, .iiабо .mi". Чи зможете ви зберегти кілька байт, збереживши файл у чомусь, a.iа не використовувати прапор?
Мартін Ендер

@ MartinBüttner Так, я помітив і це в посібнику. Тож я б очікував, що щось подібне cat>i.i;cpp -o- i.i|sed 1dбуде рівнозначним. Але відбувається повна попередня обробка (наприклад, вставляється повний вміст stdio.h). Можлива помилка gcc ??? Ну, можливо, я перевірю джерело cpp, коли отримаю мо '.
Digital Trauma

Ви можете видалити, |sed 1dякщо ви додасте -Pопцію. Зауважте, що (як це дозволяє питання), оскільки він очікує попередньо обробленого коду, він не буде обробляти триграфи або продовження рядків належним чином.
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;}}

Безумовно

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 байти

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

Як ви бачите тут , регулярний випадок складається з 2 змінних груп захоплення. Перший фіксує всі цитовані рядки. Другий - всі коментарі.

Все, що нам потрібно зробити, - це зняти все, що захопило 2-а група.

Приклад:

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

Ребол - 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]

Недоліковані + кілька приміток:

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 Ender для php:

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

тепер $strвтратив одно- та багаторядкові коментарі. Це корисно для зняття коментарів у даних JSON перед подачею до json_decode().


Можливо, ви могли б зменшити кількість байтів, використовуючи потрійний оператор?
Матьє Родіч

0

C # (262 символів):

Від цього дуже хороший 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 символів (ворс)

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

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

Натхненний моїми міні-фіксаторами, кодованими кодами: http://xem.github.io/miniMinifier/

ще не обробляє коментарі в рядках ...

Мені цікаво побачити, чи можна цього досягти в регексах JS.


Якщо ця відповідь не відповідає вимогам, її слід або виправити, або видалити.
mbomb007
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.