Select Page

compare-differences-persons-after

The Apache Commons Text library comes with some nifty string comparison routines which is nicely demonstrated by Baeldung in his Introduction to Apache Commons Text.

Instead of only calculating the difference, I wanted to visually display those differences to the user as shown above. To accomplish this I used the CommandVisitor interface to iterate through the differences and mark them appropriately.

final String left = "Phillips";
final String right = "Phillip";

MarkupCommandVisitor visitor = new MarkupCommandVisitor();
new StringsComparator(left, right).getScript().visit(visitor);

System.out.println(visitor.getMarkup());

Here is the implementation of the MarkupCommandVisitor demonstrating how the insert and delete differences are marked up between the two strings.

static class MarkupCommandVisitor implements CommandVisitor {

    private static final String CLASS_INSERT = "diff_insert";
    private static final String CLASS_DELETE = "diff_delete";
    private static final String SPAN_PREFIX = "";
    private static final String SPAN_END = "";

    /**
     * A map containing the command and the CSS class
     */
    private Map markUpCommands = new HashMap<>();
    /**
     * The current command
     */
    private Command command = Command.NONE;
    /**
     * The buffer for the diff text
     */
    private StringBuffer buffer = new StringBuffer();

    public MarkupCommandVisitor() {
        this.markUpCommands.put(Command.DELETE, CLASS_DELETE);
        this.markUpCommands.put(Command.INSERT, CLASS_INSERT);
    }

    public String getMarkup() {
        if (isCurrentMarkupCommand()) {
            visit(Command.END, Optional.empty());
        }

        return this.buffer.toString();
    }

    public void visitInsertCommand(final Character character) {
        visit(Command.INSERT, Optional.of(character));
    }

    public void visitKeepCommand(final Character character) {
        visit(Command.KEEP, Optional.of(character));
    }

    public void visitDeleteCommand(final Character character) {
        visit(Command.DELETE, Optional.of(character));
    }

    private void visit(final Command nextCommand, final Optional character) {

        if (!isCurrentCommand(nextCommand)) {
            /* Close off the current marked-up command */
            if (isCurrentMarkupCommand()) {
                buffer.append(SPAN_END);
            }
            /* Open the next marked-up command */
            if (isMarkupCommand(nextCommand)) {
                buffer.append(SPAN_PREFIX);
                buffer.append(this.markUpCommands.get(nextCommand));
                buffer.append(SPAN_POSTFIX);
            }
        }
        character.ifPresent(buffer::append);
        command = nextCommand;
    }

    private boolean isMarkupCommand(final Command command) {
        return this.markUpCommands.containsKey(command);
    }

    private boolean isCurrentMarkupCommand() {
        return this.markUpCommands.containsKey(this.command);
    }

    private boolean isCurrentCommand(final Command command) {
        return this.command == command;
    }
}

Here is how the original screen used to look without the HTML markup to indicate that the two strings were different.

compare-differences-persons-before

The code is available on GitHub at https://github.com/markash/threesixty-tutorial.