Генерация отформатированного вывода diff в Java - PullRequest
17 голосов
/ 26 ноября 2008

Существуют ли какие-либо библиотеки для Java, которые будут принимать две строки и возвращать строку с форматированным выводом согласно команде * nix diff?

например. подача

test 1,2,3,4
test 5,6,7,8
test 9,10,11,12
test 13,14,15,16

и

test 1,2,3,4
test 5,6,7,8
test 9,10,11,12,13
test 13,14,15,16

в качестве ввода, и это даст вам

test 1,2,3,4                                                    test 1,2,3,4
test 5,6,7,8                                                    test 5,6,7,8
test 9,10,11,12                                               | test 9,10,11,12,13
test 13,14,15,16                                                test 13,14,15,16

Точно так же, как если бы я передал файлы diff -y expected actual

Я нашел этот вопрос , и он дает несколько полезных советов по общим библиотекам для получения программного вывода, но я хочу получить результаты в виде прямой строки.

Я мог бы вызвать diff напрямую как системный вызов, но это конкретное приложение будет работать на Unix и Windows, и я не могу быть уверен, что в действительности в среде будет diff доступным.

Ответы [ 5 ]

14 голосов
/ 24 февраля 2011

Java-Diff-Utils

Библиотека DiffUtils для вычислений diffs, применение патчей, generationg бок о бок в Java

Библиотека Diff Utils является OpenSource библиотека для проведения сравнения операции между текстами: вычисления различия, применение патчей, генерация унифицированные различия или их разбор, генерация различий для легкого будущего отображение (как вид сбоку) и так далее.

Основная причина создания этой библиотеки была отсутствие простых в использовании библиотек с все обычные вещи, которые вам нужны в то время как работа с файлами различий. Первоначально это был вдохновлен библиотекой JRCS, и это хороший дизайн модуля diff.

Основные характеристики

  • вычисление разницы между двумя текстами.
  • способен передать больше, чем просто аскки. Массивы или Список любого типа, который реализует hashCode () и equals () правильно может быть предметом дифференцирование с использованием этой библиотеки
  • патч и распаковка текста с данным патчем
  • парсинг унифицированного формата diff
  • создавая читабельные различия
6 голосов
/ 26 ноября 2008

Я закончила свою собственную. Не уверен, что это лучшая реализация, и она безобразна, но она не соответствует тестовым данным.

Он использует java-diff для выполнения тяжелой различий (любые общие Apache StrBuilder и StringUtils вместо стандартного Java StringBuilder)

public static String diffSideBySide(String fromStr, String toStr){
    // this is equivalent of running unix diff -y command
    // not pretty, but it works. Feel free to refactor against unit test.
    String[] fromLines = fromStr.split("\n");
    String[] toLines = toStr.split("\n");
    List<Difference> diffs = (new Diff(fromLines, toLines)).diff();

    int padding = 3;
    int maxStrWidth = Math.max(maxLength(fromLines), maxLength(toLines)) + padding;

    StrBuilder diffOut = new StrBuilder();
    diffOut.setNewLineText("\n");
    int fromLineNum = 0;
    int toLineNum = 0;
    for(Difference diff : diffs) {
        int delStart = diff.getDeletedStart();
        int delEnd = diff.getDeletedEnd();
        int addStart = diff.getAddedStart();
        int addEnd = diff.getAddedEnd();

        boolean isAdd = (delEnd == Difference.NONE && addEnd != Difference.NONE);
        boolean isDel = (addEnd == Difference.NONE && delEnd != Difference.NONE);
        boolean isMod = (delEnd != Difference.NONE && addEnd != Difference.NONE);

        //write out unchanged lines between diffs
        while(true) {
            String left = "";
            String right = "";
            if (fromLineNum < (delStart)){
                left = fromLines[fromLineNum];
                fromLineNum++;
            }
            if (toLineNum < (addStart)) {
                right = toLines[toLineNum];
                toLineNum++;
            }
            diffOut.append(StringUtils.rightPad(left, maxStrWidth));
            diffOut.append("  "); // no operator to display
            diffOut.appendln(right);

            if( (fromLineNum == (delStart)) && (toLineNum == (addStart))) {
                break;
            }
        }

        if (isDel) {
            //write out a deletion
            for(int i=delStart; i <= delEnd; i++) {
                diffOut.append(StringUtils.rightPad(fromLines[i], maxStrWidth));
                diffOut.appendln("<");
            }
            fromLineNum = delEnd + 1;
        } else if (isAdd) {
            //write out an addition
            for(int i=addStart; i <= addEnd; i++) {
                diffOut.append(StringUtils.rightPad("", maxStrWidth));
                diffOut.append("> ");
                diffOut.appendln(toLines[i]);
            }
            toLineNum = addEnd + 1; 
        } else if (isMod) {
            // write out a modification
            while(true){
                String left = "";
                String right = "";
                if (fromLineNum <= (delEnd)){
                    left = fromLines[fromLineNum];
                    fromLineNum++;
                }
                if (toLineNum <= (addEnd)) {
                    right = toLines[toLineNum];
                    toLineNum++;
                }
                diffOut.append(StringUtils.rightPad(left, maxStrWidth));
                diffOut.append("| ");
                diffOut.appendln(right);

                if( (fromLineNum > (delEnd)) && (toLineNum > (addEnd))) {
                    break;
                }
            }
        }

    }

    //we've finished displaying the diffs, now we just need to run out all the remaining unchanged lines
    while(true) {
        String left = "";
        String right = "";
        if (fromLineNum < (fromLines.length)){
            left = fromLines[fromLineNum];
            fromLineNum++;
        }
        if (toLineNum < (toLines.length)) {
            right = toLines[toLineNum];
            toLineNum++;
        }
        diffOut.append(StringUtils.rightPad(left, maxStrWidth));
        diffOut.append("  "); // no operator to display
        diffOut.appendln(right);

        if( (fromLineNum == (fromLines.length)) && (toLineNum == (toLines.length))) {
            break;
        }
    }

    return diffOut.toString();
}

private static int maxLength(String[] fromLines) {
    int maxLength = 0;

    for (int i = 0; i < fromLines.length; i++) {
        if (fromLines[i].length() > maxLength) {
            maxLength = fromLines[i].length();
        }
    }
    return maxLength;
}
0 голосов
/ 06 июня 2019

Вы можете использовать Apache Commons Text библиотека для достижения этой цели. Эта библиотека предоставляет возможность 'diff', основанную на "очень эффективном алгоритме от Eugene W. Myers".

Это дает вам возможность создать своего собственного посетителя, чтобы вы могли обрабатывать diff по своему усмотрению, а также выводить его на консоль, HTML и т. Д. Вот одна статья, которая проходит через хороший и простой пример вывода diff в формате HTML с использованием библиотеки текста Apache Commons и простого кода Java.

0 голосов
/ 26 ноября 2008

http://c2.com/cgi/wiki?DiffAlgorithm Я нашел это в Google, и это дает хороший фон и ссылки. Если вам важен алгоритм, выходящий за рамки простого выполнения проекта, книга по базовому алгоритму, посвященная динамическому программированию, или книга, посвященная только этому. Алгоритм знаний всегда хорош :)

0 голосов
/ 26 ноября 2008

Busybox имеет очень простую реализацию diff, которую не сложно преобразовать в java, но вам придется добавить функциональность с двумя столбцами.

...