在Java中生成格式化的diff输出

mad*_*lep 20 java diff

是否有任何Java库可以接受两个字符串,并根据*nix diff命令返回带格式化输出的字符串?

例如,进食

test 1,2,3,4
test 5,6,7,8
test 9,10,11,12
test 13,14,15,16
Run Code Online (Sandbox Code Playgroud)

test 1,2,3,4
test 5,6,7,8
test 9,10,11,12,13
test 13,14,15,16
Run Code Online (Sandbox Code Playgroud)

作为输入,它会给你

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
Run Code Online (Sandbox Code Playgroud)

与我传递文件完全相同 diff -y expected actual

我发现了这个问题,它为一般库提供了一些很好的建议,为你提供程序化输出,但我想要直接的字符串结果.

我可以diff直接调用系统调用,但这个特定的应用程序将在unix和windows上运行,我不能确定环境实际上是否diff可用.

Mad*_*sen 14

Java的DIFF-utils的

DiffUtils库用于计算差异,应用补丁,生成Java中的并排视图

Diff Utils库是一个OpenSource库,用于执行文本之间的比较操作:计算差异,应用补丁,生成统一差异或解析它们,生成差异输出以便于将来显示(如并排视图)等.

构建这个库的主要原因是缺少易于使用的库,其中包含处理diff文件时所需的所有常用内容.最初它的灵感来自JRCS库,它是diff模块的好设计.

主要特点

  • 计算两个文本之间的差异.
  • 能比普通的ascci更有能力.正确实现hashCode()和equals()的任何类型的数组或列表都可以使用此库进行差分
  • 使用给定的补丁修补和取消文本
  • 解析统一的diff格式
  • 产生人类可读的差异


mad*_*lep 6

我最终滚动了自己.不确定它是否是最好的实现,并且它很丑陋,但它会通过测试输入.

它使用java-diff来进行重度差异提升(任何apache commons 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;
}
Run Code Online (Sandbox Code Playgroud)