Удалить однострочные и многострочные комментарии из строки


19

Цель

Используя язык программирования по вашему выбору, напишите самую короткую программу, чтобы исключить комментарии из строки, представляющей программу на Си.


вход

Строка может быть принята как любая форма ввода, но она также может быть принята как переменная.


инструкции

Два разных вида комментариев должны быть удалены:

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

Комментарии внутри строк не должны быть удалены. Для этой задачи вам нужно только рассмотреть "строки -delimited. В частности, вы можете игнорировать возможность '-ограниченных литералов символов. Вы также можете игнорировать триграфы и продолжения строк ( /\<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");появилось в должен стать кодом?
manatwork

Ой, прости ... это была просто опечатка. Спасибо, что заметили!
Матье Родик,

Учитываются ли пробелы? Есть 4 пробела, перед // this comment will be removedкоторыми просто исчезли. Любое правило для этого?
manatwork

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

Коллекция компиляторов оболочки + coreutils + gcc, 31 байт

Этот ответ может показаться немного странным, но я не видел ничего, что бы конкретно запретило его в этом вопросе.

Вместо использования неуклюжих регулярных выражений, почему бы не использовать инструмент, созданный для этой работы. Не должно быть проблем с получением правильных результатов:

cpp -fpreprocessed -o- -|sed 1d

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


1
msgstr "-fpreprocessed неявно, если входной файл имеет одно из расширений .i, .iiили .mi". Вы могли бы сохранить некоторые байты, сохранив файл в чем-то вроде, a.iвместо использования флага?
Мартин Эндер

@ MartinBüttner Да, я тоже заметил это в руководстве. Так что я ожидаю, что что-то вроде cat>i.i;cpp -o- i.i|sed 1dбудет эквивалентным. Но происходит полная предварительная обработка (например, вставляется полное содержимое stdio.h). Возможная ошибка gcc ??? Ну, возможно, я проверю исходники cpp, когда получу mo '.
Цифровая травма

Вы можете удалить, |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;}}

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

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]

Ungolfed + некоторые аннотации:

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 символов (wip)

ДЕМО: 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.