Facebook Interview Question
Software Engineer / DevelopersCountry: UK
Interview Type: Phone Interview
public class RemoveComment {
public static void main(String[] args) {
String commentString = "Hello /* this is a table */ Prashant";
String val = remove(commentString.toCharArray());
System.out.println("Final String == "+val);
}
public static String remove(char str[]) {
boolean commentStringStart = false;
boolean commentStringEnd = false;
String finalString = "";
for(int i = 0; i < str.length ; i++) {
if(str[i] == '/') {
if(str[i+1] == '*') {
commentStringStart = true;
}
}
if(str[i] == '*') {
if(str[i+1] == '/' && commentStringStart) {
commentStringEnd = true;
i = i + 1;
continue;
}
}
if(!commentStringStart || commentStringEnd) {
finalString = finalString + str[i];
}
}
return finalString;
}
}
1. split the input string on "//". anything to right of "//" is a comment. Hence work on the 0th element after split.
2. split on "/*"
3. First element is always valid. for subsequent elements check if it contains "*/", if yes then the second part is valid else the whole element is a comment.
public void printNonComments(){
while(true){
String result = "";
String str = getNextLine();
String[] a = str.split("//");
str = a[0];
a = str.split("/\\*");
int i=1;
for(String s1 : a){
if(s1.contains("*/")){
String[] b = s1.split("\\*/");
result = result + b[1] + " ";
}else{
if(i==1)
result = result + s1 + " ";
}
i++;
}
System.out.println(result.trim());
}
}
import java.io.BufferedReader;
import java.io.FileReader;
public class TestProgram {
public static final char SLASH = '/';
public static final char ASTERISK = '*';
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("/Users/admin/Input.txt"));
boolean hasCommented = false;
String line = br.readLine();
while(line!=null){
int length = line.length();
for(int i=0;i<length;i++){
if(line.charAt(i)==SLASH && line.charAt(i+1)==ASTERISK){
hasCommented = true;
i++;
continue;
}else if(hasCommented && line.charAt(i)==ASTERISK && line.charAt(i+1)==SLASH){
hasCommented = false;
i++;
}else if(!hasCommented)
System.out.print(String.valueOf(line.charAt(i)));
}
line = br.readLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null)
try {
br.close();
} catch (Exception e2) {
// ignore
}
}
}
}
public static void Main(string[] args)
{
StreamReader reader = new StreamReader(@"D:\Users\Prateek\Source\Repos\GitSyncTest\SampleCodes\SampleCodes\Files\TextFile1.txt");
StringBuilder buffer = new StringBuilder();
bool starComment = false;
while(!reader.EndOfStream)
{
bool commentLine = false;
string line = reader.ReadLine();
for(int i =0; i<line.Length; i++)
{
if (starComment)
{
if (line[i] == '*')
{
if (i + 1 == line.Length)
{
break;
}
if (line[i + 1] == '/')
{
starComment = false;
i++;
continue;
}
}
}
else
{
if (line[i] != '/')
buffer.Append(line[i]);
else
{
if (line[i + 1] != '/' && line[i + 1] != '*')
{
buffer.Append(line[i]);
}
else if (line[i + 1] == '/')
{
commentLine = true;
break;
}
else if (line[i + 1] == '*')
{
starComment = true;
i += 2;
while (i < line.Length)
{
if (line[i] == '*')
{
if ((i + 1) == line.Length)
{
line = reader.ReadLine();
break;
}
else if (line[i + 1] == '/')
{
starComment = false;
i++;
break;
}
}
else
i++;
}
}
}
}
}
if(!starComment && !commentLine)
buffer.AppendLine();
}
Console.WriteLine(buffer.ToString());
Console.ReadKey();
}
First check if the charAt gives / at i , if yes check if i+1 contains * or another /. If yes put comment is true. And don't print any character folllowing that Else print it out. If you encounter * followed by /, put comment as false. Once reading a line is completed, we can set slash comment to be false.
public static void printNonComments(String fileName) throws IOException {
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
String line;
boolean slashComment = false;
boolean starComment = false;
while ((line = br.readLine()) != null) {
boolean printed = false;
for (int i = 0; i < line.length(); i++) {
if (line.charAt(i) == '/' && (i + 1) < line.length()) {
if (line.charAt(i + 1) == '/')
slashComment = true;
else if (line.charAt(i + 1) == '*')
starComment = true;
}
if (!starComment && !slashComment) {
System.out.printf("%c", line.charAt(i));
printed = true;
}
if (line.charAt(i) == '*' && (i + 1) < line.length()) {
if (line.charAt(i + 1) == '/') {
starComment = false;
i = i + 1;
}
}
}
if (slashComment)
slashComment = false;
if (printed)
System.out.printf("\n");
}
br.close();
fr.close();
}
import java.io.BufferedReader;
import java.io.FileReader;
public class TestProgram {
public static final char SLASH = '/';
public static final char ASTERISK = '*';
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("/Users/admin/Input.txt"));
boolean hasCommented = false;
String line = br.readLine();
while(line!=null){
int length = line.length();
for(int i=0;i<length;i++){
if(line.charAt(i)==SLASH && line.charAt(i+1)==ASTERISK){
hasCommented = true;
i++;
continue;
}else if(hasCommented && line.charAt(i)==ASTERISK && line.charAt(i+1)==SLASH){
hasCommented = false;
i++;
}else if(!hasCommented)
System.out.print(String.valueOf(line.charAt(i)));
}
line = br.readLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null)
try {
br.close();
} catch (Exception e2) {
// ignore
}
}
}
}
My approach would be scan each character by character and determine if they are comments or not. This considers the occurrence of //,/*.*/, ".
package cc.commentremover;
import java.util.ArrayList;
public class CommentRemover {
ArrayList<String> text;
int readCount;
public CommentRemover() {
readCount = 0;
text = new ArrayList<String>();
text.add("This is/* \"a\" */text but followin is \" \\*string *\\\"");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
CommentRemover remover = new CommentRemover();
System.out.printf("Input Text: %s \n", remover.text.toArray());
System.out.print("Output Text: ");
remover.removeComment();
}
public String getNextLine() {
if (readCount >= text.size()) {
return null;
} else {
return text.get(readCount++);
}
}
public void removeComment() {
Boolean isComment = false;
int prevEncounter[] = { 0, 0, 0 };
String nextLine = getNextLine();
while (nextLine != null) {
char nextLinecharArray[] = nextLine.toCharArray();
int pos = 0;
while (pos < nextLinecharArray.length) {
if (nextLinecharArray[pos] == '"' && isComment == false) {
if (prevEncounter[2] != 1) {
prevEncounter[2] = 1;
} else {
prevEncounter[2] = 0;
}
} else if (nextLinecharArray[pos] == '/'
&& prevEncounter[2] == 0 && isComment == false) {
pos++;
if (nextLinecharArray[pos] == '*') {
isComment = true;
prevEncounter[1] = 1;
pos++;
continue;
} else if (nextLinecharArray[pos] == '/') {
isComment = true;
prevEncounter[0] = 1;
pos++;
continue;
} else {
pos--;
}
} else if (nextLinecharArray[pos] == '*'
&& prevEncounter[2] == 0 && isComment == true
&& prevEncounter[1] == 1) {
pos++;
if (nextLinecharArray[pos] == '/') {
isComment = false;
prevEncounter[1] = 0;
pos++;
continue;
}
} else if (pos == (nextLinecharArray.length - 1)
&& prevEncounter[2] != 1 && isComment == true
&& prevEncounter[0] == 1) {
prevEncounter[0] = 0;
isComment = false;
continue;
}
if (!isComment) {
System.out.print(nextLinecharArray[pos++]);
} else {
pos++;
}
}
nextLine = getNextLine();
}
}
}
Only consider /* */ block, not //
<?php
function printNonComments()
{
$inComment = false;
while ($line = getNextLine()) {
$search = $inComment ? '*/' : '/*';
$pos = strpos($line, $search);
while ($pos !== false) {
if (!$inComment) echo substr($line, 0, $pos);
$line = substr($line, $pos + 2);
$inComment = !$inComment;
$search = $inComment ? '*/' : '/*';
$pos = strpos($line, $search);
}
!$inComment ? echo $line : echo "\n";
}
echo "\n";
}
$lines = [
'hello /* this is a ',
'multi line comment */ all',
];
function getNextLine()
{
global $lines;
$line = reset($lines);
if (!$line) return null;
$key = key($lines);
unset($lines[$key]);
return $line;
}
printNonComments();
public void printNonComments(String text)
{
boolean activeComment = false;
System.out.println("input text: " + text);
for(int i=0; i<text.length()-1; i++)
{
String textToCompare = "" + text.charAt(i) + text.charAt(i+1);
//System.out.println("current text to compare: " + textToCompare);
if(textToCompare.equals( "/*"))
{
//System.out.println("FOUND A COMMENT ----------");
activeComment = true;
//i=i+2;
}
else if (textToCompare.equals("*/"))
{
activeComment = false;
i=i+1;
}
else if(activeComment == false || textToCompare.contains("\r"))
{
System.out.print(text.charAt(i));
}
}
if(activeComment == false)
{
System.out.print(text.charAt(text.length()-1));
}
}
h public void printNonComments(String text)
{
boolean activeComment = false;
System.out.println("input text: " + text);
for(int i=0; i<text.length()-1; i++)
{
String textToCompare = "" + text.charAt(i) + text.charAt(i+1);
//System.out.println("current text to compare: " + textToCompare);
if(textToCompare.equals( "/*"))
{
//System.out.println("FOUND A COMMENT ----------");
activeComment = true;
//i=i+2;
}
else if (textToCompare.equals("*/"))
{
activeComment = false;
i=i+1;
}
else if(activeComment == false || textToCompare.contains("\r"))
{
System.out.print(text.charAt(i));
}
}
if(activeComment == false)
{
System.out.print(text.charAt(text.length()-1));
}
}
public static final String COMMENTS = "/\\*(?:.|[\\n\\r])*?\\*/";
private String printNoComments() {
StringBuffer buffer = new StringBuffer();
String currentLine = getNextLine();
while (!currentLine.isEmpty()) {
buffer.append(getNextLine().replaceAll(COMMENTS, ""));
}
return buffer.toString();
}
static string RemoveComments(List<string> strs)
{
bool isInComment = false;
StringBuilder result = new StringBuilder();
foreach (string str in strs)
{
char next = Char.MinValue, current;
for (int i = 0; i < str.Length; i++)
{
current = str[i];
if (i < str.Length - 1)
{
next = str[i + 1];
}
if (!isInComment)
{
if (current == '/' && next == '*' || current == '/' && next == '/')
{
isInComment = true;
if (next == '/')
break;
i++;
}
else
{
result.Append(current);
}
}
else
{
if (next == '/' && current == '*')
{
isInComment = false;
i++;
}
}
}
result.Append('\n');
}
return result.ToString();
}
#include <iostream>
#include <string>
using namespace std;
void parse(string s, bool multiline = false) {
size_t m_end = s.find("*/");
if (multiline && m_end == string::npos) {
return;
}
int n = s.size();
string output = "";
size_t m_start = s.find("/*");
if (m_start != string::npos) {
output += string(s,0,(int)m_start);
}
size_t s_start = s.find("//");
if (m_end != string::npos) {
int end = s_start!=string::npos? s_start-1: n-1;
output += string(s,m_end+2,end-m_end-1);
} else if (s_start != string::npos) {
output += string(s,0,(int)s_start);
} else if (m_start == string::npos) {
output += s;
}
cout << "output : " << output << "\n";
}
int main() {
parse("abc//def");
parse("abc/*def");
parse("abc/*def*/ xyz");
parse("asd*/def", true);
parse("asd*/def // sd", true);
parse("asd*/", true);
parse("// asd");
}
Assuming reading from text file
package com.cnu.ds;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
class Test {
public static void printNonComments() {
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
new File("text")));
String line = null;
boolean isComment = false;
while ((line = bufferedReader.readLine()) != null) {
for (int i = 0; i < line.length() - 1; i += 1) {
if ((line.charAt(i) == '/') && (line.charAt(i + 1) == '*')) {
isComment = true;
continue;
}
if ((line.charAt(i) == '*') && (line.charAt(i + 1) == '/')) {
isComment = false;
continue;
}
if (!isComment && line.charAt(i) != '/') {
System.out.print("" + line.charAt(i));
}
}
if (!isComment) {
System.out.println(line.charAt(line.length() - 1));
} else
System.out.println();
}
bufferedReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
printNonComments();
}
}
import sys
def getNextLine():
return sys.stdin.readline()
def printNonComments():
comments=False
while 1:
line=getNextLine()
if not line:
return
if r'//' in line:
line=line[:line.index(r'//')]
if comments is True:
if r'*/' in line:
comments=False
line=line[line.rindex(r'*/')+2:]
print line
else:
continue
else:
if r'/*' in line:
line=line[:line.index(r'/*')]
print line
comments=True
else:
print line
printNonComments()
public static void main(String[] args) {
String input = "hello /* this is a \n" +
"multi line comment */ all ";
StringBuilder result = new StringBuilder();
boolean commentStarted = false;
String[] lines = input.split("\n");
StringBuilder lineB = new StringBuilder();
for (String line : lines) {
lineB.append(line);
int startCommentIndex = lineB.indexOf("/*");
int endCommentIndex = lineB.indexOf("*/");
int start = 0;
int end = 0;
if (startCommentIndex != -1) {
start = startCommentIndex;
commentStarted = true;
}
if (endCommentIndex != -1)
end = endCommentIndex + 2;
else
end = lineB.length();
if (commentStarted) {
result.append(lineB.replace(start, end, ""));
}
if (endCommentIndex != -1)
commentStarted = false;
lineB.delete(0, lineB.length());
}
System.out.print(result.toString());
}
A stack can be used to do this.
1) Push each word to the stack. Keep a note of the word if it is or contains the comment character like /* or //. New line character should be considered as a word.
2) If */ or \n occurred later on and we have seen /* or // respectively, pop all words off the stack till the world /* or the word that contains /* or //.
3) Once all lines are parsed, pop all words off the stack and display them (need to reverse the string).
This can be done character by character but, its expensive I feel.
public class RemoveComments {
private static boolean inComment;
public static String removeComment(String input) {
if (inComment) {
int commentEndIndex = input.indexOf("*/");
if (commentEndIndex == -1)
return "";
inComment = false;
return removeComment(input.substring(commentEndIndex+2));
}
int commentStartIndex = input.indexOf("/*");
if (commentStartIndex != -1) {
inComment=true;
return input.substring(0, commentStartIndex) + removeComment(input.substring(commentStartIndex));
}
return input;
}
Using c++11, find starting and ending index of the string. Count newlines in between comments and append them in the middle. This assumes string is given as input.
Compile on LInux with:
g++ -std=c++11 testExtractMultiLine.cpp -o extract_multi_line
#include<stdio.h>
#include<stdint.h>
#include<string>
using std::string;
const string testString = string("hello /* this is a\nmulti line comment */ all");
const string COMMENT_START = string("/*");
const string COMMENT_END = string("*/");
const string NEW_LINE = string("\n");
string RemoveComments(string inString)
{
string retString;
size_t commentStart = inString.find(COMMENT_START);
size_t commentEnd = inString.rfind(COMMENT_END) + 2;
size_t idx = 0;
size_t newLineIdx = 0;
uint32_t newLineCnt = 0;
//Find all new lines within comment block
newLineIdx = inString.find_first_of(NEW_LINE);
while(newLineIdx < commentEnd && newLineIdx != string::npos) {
if(newLineIdx > commentStart) {
newLineCnt++;
}
newLineIdx = inString.find_first_of(NEW_LINE, newLineIdx+1);
}
retString.append(inString.substr(0, commentStart));
for(uint32_t ctr = 0; ctr < newLineCnt; ctr++) {
retString.append(NEW_LINE);
}
retString.append(inString.substr(commentEnd,
inString.size() - (commentEnd)));
return retString;
}
int main(int argc, char *argv[])
{
string noComments = RemoveComments(testString);
printf("Removing comment from:\n\"%s\"\n\n", testString.c_str());
printf("Result string:\n\"%s\"\n", noComments.c_str());
return 0;
}
// vim: softtabstop=4:shiftwidth=4:expandtab
Output:
$ ./extract_multi_line
Removing comment from:
"hello /* this is a
multi line comment */ all"
Result string:
"hello
all"
And after re-reading the problem description, I did not implement this exactly as requested in the problem. :)
Single comment block check only. Won't work on 'hello /* c1 */ all /* c2 */ guys' case.
In C++ Solution, which's comment strarts with "Using c++11, find starting and ending...", you need only add recursion at the end (before return) and everything will work fine:
std::string removeComments(const std::string inputString)
{
const std::string COMMENT_START("/*");
const std::string COMMENT_END("*/");
const std::string NEW_LINE("\n");
size_t commentStart = inputString.find(COMMENT_START);
size_t commentEnd = inputString.find(COMMENT_END)+2;
size_t idx = 0;
size_t newLineIdx = 0;
size_t newLineCnt = 0;
// Find all new-lines within comment block
newLineIdx = inputString.find(NEW_LINE);
while (newLineIdx < commentEnd && newLineIdx != std::string::npos)
{
if (newLineIdx > commentStart)
newLineCnt++;
newLineIdx = inputString.find_first_of(NEW_LINE, newLineIdx + 1);
}
std::string retString;
retString.append(inputString.substr(0, commentStart));
for (int ctr = 0; ctr < newLineCnt; ctr++) {
retString.append(NEW_LINE);
}
retString.append(inputString.substr(commentEnd, inputString.size() - (commentEnd)));
if (retString.find(COMMENT_START) != std::string::npos)
retString = removeComments(retString);
return retString;
}
def nextLine(x):
for i in x.split('\n'):
yield i
def print_noncomment(input):
is_commented = False
for l in nextLine(input):
if is_commented:
if '*/' in l:
l = l[l.find('*/')+len('*/'):]
is_commented = False
else:
l = ''
elif not is_commented:
if '/*' in l and '*/' in l and l.find('*/') > l.find('/*'):
l = l[:l.find('/*')]+l[l.find('*/')+2:]
elif '/*' in l:
l = l[:l.find('/*')]
is_commented = True
print l
public void printNonComment(){
String x = "hello /* this is a \n" +
"multi line comment */ all ";
boolean isCommentZone= false;
for(int i=0;i<x.length();i++){
if(!isCommentZone && x.charAt(i)=='/'){
isCommentZone = true;
}
else if(isCommentZone && x.charAt(i)=='/'){
isCommentZone = false;
}
else if (!isCommentZone) {
System.out.print(x.charAt(i));
}
}
}
public void printNonComment(){
String x = "hello /* this is a \n" +
"multi line comment */ all ";
boolean isCommentZone= false;
for(int i=0;i<x.length();i++){
if(!isCommentZone && x.charAt(i)=='/'){
isCommentZone = true;
}
else if(isCommentZone && x.charAt(i)=='/'){
isCommentZone = false;
}
else if (!isCommentZone) {
System.out.print(x.charAt(i));
}
}
}
For single line comments parse the current line until you find '//' then ignore anything that follows it (including the double slashes).
- Anonymous June 30, 2014If you encounter '/*', then call nextLine() until you encounter '*/' and remove anything in between.
Another thing to pay attention to is, and this is at the discretion of the interviewer, to watch out for comment characters within double quotes like "//" or "/* */", these wouldn't be considered comments and removing anything in between would be wrong.
Other than the odd edge case, this problem seems to be straightforward enough. And, if you did mention those edge cases, I believe the interviewer would steer you in the correct direction.