21

是否有任何 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可用。

4

5 回答 5

15

java-diff-utils

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

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

构建这个库的主要原因是缺乏易于使用的库,其中包含您在处理差异文件时需要的所有常用内容。最初它受到 JRCS 库的启发,它是 diff 模块的不错设计。

主要特点

  • 计算两个文本之间的差异。
  • 能够比普通的ASCII码更多。正确实现 hashCode() 和 equals() 的任何类型的数组或列表都可以使用此库进行差分
  • 使用给定的补丁修补和取消修补文本
  • 解析统一差异格式
  • 产生人类可读的差异
于 2011-02-24T14:39:49.510 回答
6

我最终滚动了自己的。不确定它是否是最好的实现,它丑得要命,但它通过了测试输入。

它使用java-diff进行繁重的 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;
}
于 2008-11-26T05:42:50.203 回答
0

Busybox 有一个非常精简的 diff 实现,应该不难转换为 java,但您必须添加两列功能。

于 2008-11-26T01:31:34.190 回答
0

http://c2.com/cgi/wiki?DiffAlgorithm我在 Google 上找到了这个,它提供了一些很好的背景和链接。如果你关心的不仅仅是做项目的算法,一本涵盖动态编程的基本算法的书或一本关于它的书。算法知识总是好的:)

于 2008-11-26T01:59:39.907 回答
0

您可以使用Apache Commons Text库来实现这一点。该库基于“来自 Eugene W. Myers 的非常有效的算法”提供了“差异”功能。

这使您能够创建自己的访问者,以便您可以以您想要的方式处理差异,并且可以输出到控制台或 HTML 等。这是一篇文章,介绍了在 HTML 中并排输出差异的简单示例使用 Apache Commons Text 库和简单的 Java 代码格式化。

于 2019-06-06T07:32:29.737 回答