(Previous and initial iteration lives here.)
(The next iteration is here.)
Now I was able to spare some lines by putting diff related state in an object. Also, I relied on Files.readAllLines
, as advised.
com.github.coderodde.diff.Diff.java:
package com.github.coderodde.diff;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Objects;
public class Diff {
private static final String NL = System.lineSeparator();
private static final String HELP_MESSAGE =
"java -jar Diff.jar OLD_FILE NEW_FILE";
private final List<String> oldSourceLines;
private final List<String> newSourceLines;
private final int[][] matrix;
public Diff(List<String> oldSourceLines, List<String> newSourceLines) {
this.oldSourceLines = Objects.requireNonNull(oldSourceLines);
this.newSourceLines = Objects.requireNonNull(newSourceLines);
this.matrix = new int[oldSourceLines.size() + 1]
[newSourceLines.size() + 1];
}
public String compute() {
computeLongestCommonSubsequenceMatrix();
return buildDiff();
}
public static void main(String[] args) {
if (args.length != 2) {
System.out.println(HELP_MESSAGE);
System.exit(0);
}
try {
List<String> oldSourceLines = readFile(new File(args[0]));
List<String> newSourceLines = readFile(new File(args[1]));
Diff diff = new Diff(oldSourceLines, newSourceLines);
System.out.println(diff.compute());
} catch (IOException ex) {
System.err.println("I/O failed: " + ex.getMessage());
System.exit(1);
}
}
// Reads all the file lines into a list and returns the list in question.
private static List<String> readFile(File file) throws IOException {
return Files.readAllLines(file.toPath());
}
// This algorithm solves the Longest Common Subsequence problem. The
// alphabet is not assumed to be a cuatomary alphabet, but rather all
// possible strings over a simple alphabet.
private void computeLongestCommonSubsequenceMatrix() {
for (int i = 1; i <= oldSourceLines.size(); ++i) {
for (int j = 1; j <= newSourceLines.size(); ++j) {
if (oldSourceLines.get(i - 1)
.equals(newSourceLines.get(j - 1))) {
matrix[i][j] = matrix[i - 1][j - 1] + 1;
} else {
matrix[i][j] = Math.max(matrix[i - 1][j],
matrix[i][j - 1]);
}
}
}
}
// The entry ponit for the algorithm that reconstructs the LCS from the
// matrix.
private String buildDiff() {
StringBuilder stringBuilder = new StringBuilder();
buildDiff(stringBuilder,
oldSourceLines.size() - 1,
newSourceLines.size() - 1);
return stringBuilder.toString();
}
// Reconstructs the diff ocntent from the LCS matrix.
private void buildDiff(StringBuilder stringBuilder,
int i,
int j) {
if (i >= 0
&& j >= 0
&& oldSourceLines.get(i).equals(newSourceLines.get(j))) {
buildDiff(stringBuilder,
i - 1,
j - 1);
stringBuilder.append(" ").append(oldSourceLines.get(i)).append(NL);
} else if (j > 0 && (i == 0 || matrix[i][j - 1] >= matrix[i - 1][j])) {
buildDiff(stringBuilder,
i,
j - 1);
stringBuilder.append("+ ").append(newSourceLines.get(j)).append(NL);
} else if (i > 0 && (j == 0 || matrix[i][j - 1] < matrix[i - 1][j])) {
buildDiff(stringBuilder,
i - 1,
j);
stringBuilder.append("- ").append(oldSourceLines.get(i)).append(NL);
}
}
}
Critique request
As always, please, tell me anything that comes to mind. Am I improving my toy diff?