8
\$\begingroup\$

Goal

Replace all comments in C, C++, or Java Code with the comment // Do the needful.

Specifics

This coding challenge is a simple one. Take as input the name of a file. The input file shall contain C, C++, or Java code. The code shall contain one or more comments. The comments can be single line /* */ or // delimited, as well as multi-line /* */ delimited. The output of the program should be identical to the input except all of the comments should be converted to // Do the needful.

For example if the input file is:

#include <iostream.h>

int   result;    // the result of the calculations 
char  oper_char; // the user-specified operator 
int   value;     // value specified after the operator

/* standard main function */     
int main()
{
    result = 0; // initialize the result 

    // Loop forever (or till we hit the break statement) 
    while (1) {
        cout << "Result: " << result << '\n';

        /* This code outputs display and requests
           input from the user */
        cout << "Enter operator and number: ";
        cin >> oper_char;
        cin >> value;

        if (oper_char = '+') {
            result += value;
        } else {
            cout << "Unknown operator " << oper_char << '\n';
        }
    }
    return (0);
}

The output of the program should read

#include <iostream.h>

int   result;    // Do the needful
char  oper_char; // Do the needful
int   value;     // Do the needful

// Do the needful
int main()
{
    result = 0; // Do the needful

    // Do the needful
    while (1) {
        cout << "Result: " << result << '\n';

        // Do the needful
        cout << "Enter operator and number: ";
        cin >> oper_char;
        cin >> value;

        if (oper_char = '+') {
            result += value;
        } else {
            cout << "Unknown operator " << oper_char << '\n';
        }
    }
    return (0);
}

Scoring

This is a popularity contest. You get two extra votes added to your score if none of the following words appears in your program in any case variation: {"do", "the", "needful"}. Score is number of votes plus bonus if applicable.

Allowances

If comments appear in string literals it is acceptable to convert them to // Do the needful as well. After all... you can never have enough needful.

\$\endgroup\$
11
  • 5
    \$\begingroup\$ You know that the bonus is easily acquired by using "d" + "o", "t" + "he" and "need" + "ful"? Also, does the submission have to be able to deal with any valid C, C++ or Java code? That's pretty harsh and amounts to writing a lexer for all three languages (I'm thinking about comment literals in strings and vice-versa.) If so, what about 3rd-party lexer libraries? \$\endgroup\$ May 26, 2014 at 23:55
  • 2
    \$\begingroup\$ What should the program do when a /* ... */ precedes a non-comment on a line? \$\endgroup\$ May 27, 2014 at 0:27
  • 1
    \$\begingroup\$ Do we need to consider cases like char str[]="/**///"; or a comment-start sequence /* appears in a /* comment, or a backslash-newline appears in a // comment, or a // comment within a /**/ comment? \$\endgroup\$
    – user12205
    May 27, 2014 at 0:37
  • 3
    \$\begingroup\$ Why make this a popularity contest and not code golf? It works just fine as golf. \$\endgroup\$
    – Aaronaught
    May 27, 2014 at 2:41
  • 2
    \$\begingroup\$ eventually lots of solutions are based on the same regex replacement. What about some bonus points for non regex solutions? \$\endgroup\$ May 27, 2014 at 14:34

7 Answers 7

6
\$\begingroup\$

Perl, 68 characters

perl -0pe's@((//).*?(\n)|(/\*).*?(\*/))@\2\4 Do the needful \3\5@sg'

This takes some liberties with the specification, and retains the original comment style. This avoids the problem with /* ... */ comments appearing before the end of the line.

No attempt is made to avoid comments within string literals, and no claim is made for the bonus points.

\$\endgroup\$
8
  • \$\begingroup\$ I am having a ball using this on source code! \$\endgroup\$
    – ojblass
    May 27, 2014 at 1:08
  • 2
    \$\begingroup\$ I would say it improves upon some commenting styles. \$\endgroup\$ May 27, 2014 at 1:09
  • \$\begingroup\$ You can get the bonus point like this \$\endgroup\$
    – ojblass
    May 27, 2014 at 1:23
  • \$\begingroup\$ perl -0pe 's/((\/\/).*?(\n)|(\/*).*?(*\/))/\2\4 D\coo th\coe needfu\cul \3\5/sg' \$\endgroup\$
    – ojblass
    May 27, 2014 at 1:23
  • 1
    \$\begingroup\$ @FDinoff: Yes, that was a liberty I took to simplify the problem, otherwise you have to figure out what to do with code lines where a /* ... */ comment precedes actual code (you can't naively turn it into a // comment). \$\endgroup\$ May 27, 2014 at 7:11
5
\$\begingroup\$

Perl

First world anarchy! :)

"you can never have enough needful"

#!perl -p0
sub the { s,(?<=\w)(.*)(\n),$1 // do the needful$2,g }
sub needful { s,//.*\n,\n,g,s,/\*.*?\*/,,msg }

do not do the needful
\$\endgroup\$
4
\$\begingroup\$

CoffeeScript (66 bytes)

(c)->c.replace /\/\/.*\n?|\/\*[^]*?\*\//g,"// D\o t\he needfu\l\n"

This code will parse strings, but there is a good reason. You see, there is a possibility that there is a comment in a template generating C /**/ comments.

This gets the bonus, as it avoids exact case insensitive matches for Do, the, and needful. It also uses ES5 candle ([^]) operator to do stuff. I would put a comment Do the needful in this program, but that would remove the bonus.

\$\endgroup\$
0
4
\$\begingroup\$

Python 3.x, regex

Since it's not code golf I didn't fuss about code length. Nothing impressive, but I had fun remembering / relearning regex basics.

import re
import urllib.request as r
def dTN(filename):
    dtn = re.search(r"(?<=question-hyperlink\">)([A-Za-z \n]*)(?=[?]<)", r.urlopen("http://codegolf.stackexchange.com/questions/28625/").read().decode("utf8")).group(0)
    with open(filename) as f:
        return re.sub(r"//{1}.*", "//{0}".format(dtn), re.sub(r"/\*[A-Za-z \n]*\*/", "// {0}".format(dtn), f.read()))
\$\endgroup\$
2
\$\begingroup\$

sed, 90 characters

Could be improved. I learned a lot about sed while making this.

Reads from standard input, outputs to standard output. Assumes valid input - if you have unterminated comments, it won't treat it as a comment.

Tested on GNU sed v4.2.2.

s_/\*.*\*/_//_
tg
s_/\*.*$_//_
tl
:g
s_//.*$_// Do the needful_
P
d
:l
s_.*\*/_//_
tg
N
bl

And the prize for readability goes to....?

One-liner version:

s_/\*.*\*/_//_;tg;s_/\*.*$_//_;tl;:g;s_//.*$_// Do the needful_;P;d;:l;s_.*\*/_//_;tg;N;bl

Explanation

The control flow jumps around a lot, by means of GOTO statements (yes, sed has them!). sed does not have any loops or convenient conditional statements AFAIK.

s_/\*.*\*/_//_              # Substitute /* ... */ with //
tg                          # GOTO g if the substitution occured
s_/\*.*$_//_                # Substitute /*...<ENDOFLINE> with //
tl                          # GOTO l if the substitution occured
:g                          # GOTO-LABEL g
s_//.*$_// Do the needful_  # Replace //...<ENDOFLINE> with // Do the needful
P                           # Print the pattern space (current line with substitutions)
d                           # empty the pattern space and move on to the next line
:l                          # GOTO-LABEL l
s_.*\*/_//_                 # Replace ... */ with //
tg                          # GOTO g if the substitution occured
N                           # take another line from input and add it to the pattern space
bl                          # GOTO l
\$\endgroup\$
2
\$\begingroup\$

BrainFuck

Yes, BrainFuck is a Turing-complete language.
Good luck for understanding this code.

,[.-----------------------------------------------[>+>+<<-]>
>[-<<+>>][-]+<[[-]>-<]>[>,----------------------------------
-------------[>+>+<<-]>>[-<<+>>]<>[-]+<[>-<+++++[>+>+<<-]>>[
-<<+>>]<>[-]+<[>-<++++++++++++++++++++++++++++++++++++++++++
.[-]]>[<+++++++++++++++++++++++++++++++++++++++++++++++.----
-----------.++++++++++++++++++++++++++++++++++++.+++++++++++
++++++++++++++++++++++++++++++++.---------------------------
----------------------------------------------------.+++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++.------------.---.-------------------------
--------------------------------------------.+++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++.---------..-.++.+++++++++++++++.---------.[+++++[,------
------------------------------------],----------------------
-------------------------]>-]<<[-]]>[<++++++++++++++++++++++
+++++++++++++++++++++++++.---------------.++++++++++++++++++
++++++++++++++++++.+++++++++++++++++++++++++++++++++++++++++
++.---------------------------------------------------------
----------------------.+++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++.------------
.---.-------------------------------------------------------
--------------.+++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++.---------..-.++.++++++++++
+++++.---------.[,----------]++++++++++.[-]>-]<<[-]<<>-]<<,]

Basically, the pseudo-code is :

get input_char
while (input_char is not null)
{
  print input_char
  if (input_char is '/')
  {
    get input_char
    if (input_char is '/')
    {
      print '/ Do the needful'
      get input_char until input_char is '\n'
    }
    else
    {
      if (input_char is '*')
      {
        print '/ Do the needful'
        get input_char until input_char is '*' followed by '/'
      }
      else
      {
        print input_char
      }
    }
  }
  get input_char
}

Some online interpreter are broken.
Try it here with the example given by the OP (ended with null-char to break the loop properly) :

#include <iostream.h>\n\nint   result;    // the result of the calculations \nchar  oper_char; // the user-specified operator \nint   value;     // value specified after the operator\n\n/* standard main function */     \nint main()\n{\n    result = 0; // initialize the result \n\n    // Loop forever (or till we hit the break statement) \n    while (1) {\n        cout << "Result: " << result << '\\n';\n\n        /* This code outputs display and requests\n           input from the user */\n        cout << "Enter operator and number: ";\n        cin >> oper_char;\n        cin >> value;\n\n        if (oper_char = '+') {\n            result += value;\n        } else {\n            cout << "Unknown operator " << oper_char << '\\n';\n        }\n    }\n    return (0);\n}\0
\$\endgroup\$
2
\$\begingroup\$

Rebol

It's not code golf, so I'll be wordy.

do-the-needful: function [filename [file!]] [
    parse (data: to-string read filename) [
        ; match the pattern in brackets ANY number of times (zero okay)
        any [
            ; seek the parse position up TO one of the following matches
            ; if a match is hit, following code in parentheses is executed normally
            to [
                "/*" (terminator: "*/")
            | 
                "//" (terminator: newline)
            ]

            ; save parse position in start, seek up THRU terminator and leave parse
            ; position at the end of the terminator match (not the beginning as w/TO)
            start:
            thru terminator
            finish:

            ; Do partial replacement within the input; starting at START
            ; but limited to FINISH.  Again, structure in parentheses is exec'd as code
            (
                change/part start combine ["// Do the needful" newline] finish
            )
        ]
    ]
    return data
 ]

(Note: For political reasons, I am pushing COMBINE here, but it's not standard yet. So if you actually want to run this, use REJOIN. But I hate REJOIN. A wart on an otherwise beautiful language! Tell your friendly neighborhood Red dev leads to listen to me. Thanks.)

PARSE is a dialect, or language-within-a-language, in Rebol and Red. It twists things up, so for instance the symbol types that are used for assignment (the terminator: in terminator: newline) takes on a new meaning when used in the code-as-data paradigm... it saves the current parse position into a variable with that name. You can read more about why it's cool here.


UPDATE: Oh all right, I'll golf it too. In Rebmu, 72 chars... using rebmu/args which injects A as the argument:

pa DtsRDa[anTO["/*"(T"*/")|"//"(Tlf)]SthT F(chpS"// Do the needful^/"f)]d

Exactly the same program.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.