Created
July 18, 2019 21:46
-
-
Save imyousuf/45017c1b12168145b05c4f5dde0dbf0d to your computer and use it in GitHub Desktop.
A crack at the code cleaner problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"os" | |
"sort" | |
"strings" | |
"unicode" | |
) | |
func main() { | |
params := os.Args[1:] | |
originalLines, _ := readInput(params[0]) | |
processedLines := squashWhitespaceWhenSingleLineComment(stripMultilineComments(stripSingleLineComments(originalLines))) | |
printLines(processedLines) | |
writeLines(processedLines, params[1]) | |
} | |
type marker struct { | |
Line int | |
Position int | |
} | |
var defaultMarker = marker{Line: -1, Position: -1} | |
type truncator struct { | |
Start marker | |
End marker | |
} | |
func (t *truncator) hasStarted() bool { | |
return t.Start != defaultMarker | |
} | |
func newTruncator() *truncator { | |
return &truncator{ | |
Start: defaultMarker, | |
End: defaultMarker, | |
} | |
} | |
func truncateSlice(toBeTruncatedLines []string, truncators []truncator) []string { | |
sort.Slice(truncators, func(i, j int) bool { | |
if truncators[i].Start.Line != truncators[j].Start.Line { | |
return truncators[i].Start.Line > truncators[j].Start.Line | |
} else { | |
return truncators[i].Start.Position > truncators[j].Start.Position | |
} | |
}) | |
// Now that there is a truncate list in descending order just loop through and truncate them | |
// It means lines will be squashed and entire block will be replaced with single value | |
// signified by replaceChar or left alone | |
result := make([]string, len(toBeTruncatedLines)) | |
copy(result, toBeTruncatedLines) | |
for _, truncat := range truncators { | |
if truncat.End.Line == truncat.Start.Line { | |
result[truncat.Start.Line] = result[truncat.Start.Line][:truncat.Start.Position] + result[truncat.Start.Line][truncat.End.Position:] | |
} else { | |
result[truncat.End.Line] = result[truncat.End.Line][truncat.End.Position:] | |
result[truncat.Start.Line] = result[truncat.Start.Line][:truncat.Start.Position] | |
} | |
if truncat.End.Line-truncat.Start.Line > 1 { | |
result = append(result[:truncat.Start.Line+1], result[truncat.End.Line:]...) | |
} | |
} | |
return result | |
} | |
const ( | |
startMultilineCommentMarker = "/*" | |
endMultilineCommentMarker = "*/" | |
singleLineCommentMarker = "//" | |
) | |
func stripMultilineComments(tobeProcessedLines []string) []string { | |
workingTruncator := newTruncator() | |
truncators := []truncator{} | |
for index, line := range tobeProcessedLines { | |
if !workingTruncator.hasStarted() && strings.Contains(line, startMultilineCommentMarker) { | |
workingTruncator.Start = marker{ | |
Line: index, | |
Position: strings.Index(line, startMultilineCommentMarker), | |
} | |
} | |
if workingTruncator.hasStarted() && strings.Contains(line, endMultilineCommentMarker) { | |
workingTruncator.End = marker{ | |
Line: index, | |
Position: strings.Index(line, endMultilineCommentMarker) + 2, | |
} | |
truncators = append(truncators, *workingTruncator) | |
workingTruncator = newTruncator() | |
} | |
} | |
return truncateSlice(tobeProcessedLines, truncators) | |
} | |
func stripSingleLineComments(tobeProcessedLines []string) []string { | |
workingTruncator := newTruncator() | |
truncators := []truncator{} | |
for index, line := range tobeProcessedLines { | |
if strings.Contains(line, singleLineCommentMarker) { | |
workingTruncator.Start.Line = index | |
workingTruncator.End.Line = index | |
workingTruncator.Start.Position = strings.Index(line, singleLineCommentMarker) | |
workingTruncator.End.Position = len(line) | |
truncators = append(truncators, *workingTruncator) | |
workingTruncator = newTruncator() | |
} | |
} | |
return truncateSlice(tobeProcessedLines, truncators) | |
} | |
func squashWhitespaceWhenSingleLineComment(tobeProcessedLines []string) []string { | |
// This should also replace all newline with a single white space | |
linesInSingleString := strings.Join(tobeProcessedLines, " ") | |
// Converts all type of whitespace to a single type of whitespace - the regular one | |
flattenedSingleString := "" | |
workingTruncator := newTruncator() | |
truncators := []truncator{} | |
// Tracks beginning of a whitespace patch | |
whitespace := false | |
for index, char := range linesInSingleString { | |
// Tracks - '\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP) | |
if unicode.IsSpace(char) { | |
flattenedSingleString += " " | |
if !whitespace { | |
whitespace = true | |
} else if !workingTruncator.hasStarted() { | |
workingTruncator.Start.Line = 0 | |
workingTruncator.Start.Position = index | |
} | |
} else { | |
flattenedSingleString += string(char) | |
whitespace = false | |
if workingTruncator.hasStarted() { | |
workingTruncator.End.Line = 0 | |
workingTruncator.End.Position = index | |
truncators = append(truncators, *workingTruncator) | |
workingTruncator = newTruncator() | |
} | |
} | |
} | |
return truncateSlice([]string{flattenedSingleString}, truncators) | |
} | |
func printLines(linesToPrint []string) { | |
for _, line := range linesToPrint { | |
println(line) | |
} | |
} | |
// Copied from https://stackoverflow.com/questions/5884154/read-text-file-into-string-array-and-write | |
func readInput(filepath string) ([]string, error) { | |
file, err := os.Open(filepath) | |
if err != nil { | |
return nil, err | |
} | |
defer file.Close() | |
var lines []string | |
scanner := bufio.NewScanner(file) | |
for scanner.Scan() { | |
lines = append(lines, scanner.Text()) | |
} | |
return lines, scanner.Err() | |
} | |
func writeLines(linesToWrite []string, outputFilepath string) error { | |
file, err := os.Create(outputFilepath) | |
if err != nil { | |
return err | |
} | |
defer file.Close() | |
w := bufio.NewWriter(file) | |
for _, line := range linesToWrite { | |
fmt.Fprintln(w, line) | |
} | |
return w.Flush() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include<stdio.h> | |
// This is a single line | |
int main() {/* | |
Multiline comment | |
*/ | |
// Single line comment takes priority over /* | |
return 0; // Another single line | |
// Single line comment takes priority over */ | |
/* Single line multi-line comment */ | |
/* | |
Another Multiline comment | |
*/ | |
} | |
// Output of this code is - | |
// # include<stdio.h> int main() { return 0; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment