在 Java 中生成格式化的差异输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/319479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 13:06:48  来源:igfitidea点击:

Generate formatted diff output in Java

javadiff

提问by madlep

Are there any libraries out there for Java that will accept two strings, and return a string with formatted output as per the *nix diff command?

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

e.g. feed in

例如喂食

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

and

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

as input, and it would give you

作为输入,它会给你

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

Exactly the same as if I had passed the files to diff -y expected actual

完全一样,就好像我已经将文件传递给 diff -y expected actual

I found this question, and it gives some good advice on general libraries for giving you programmatic output, but I'm wanting the straight string results.

我发现了这个问题,它提供了一些关于为您提供编程输出的通用库的好建议,但我想要直接的字符串结果。

I could call diffdirectly as a system call, but this particular app will be running on unix and windows and I can't be sure that the environment will actually have diffavailable.

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

采纳答案by madlep

I ended up rolling my own. Not sure if it's the best implementation, and it's ugly as hell, but it passes against test input.

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

It uses java-diffto do the heavy diff lifting (any apache commons StrBuilder and StringUtils instead of stock Java StringBuilder)

它使用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;
}

回答by Sparr

Busybox has a diff implementation that is very lean, should not be hard to convert to java, but you would have to add the two-column functionality.

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

回答by Jim Keener

http://c2.com/cgi/wiki?DiffAlgorithmI found this on Google and it gives some good background and links. If you care about the algorithm beyond just doing the project, a book on basic algorithm that covers Dynamic Programming or a book just on it. Algorithm knowledge is always good:)

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

回答by Mads Hansen

java-diff-utils

java-diff-utils

The DiffUtils library for computing diffs, applying patches, generationg side-by-side view in Java

Diff Utils library is an OpenSource library for performing the comparison operations between texts: computing diffs, applying patches, generating unified diffs or parsing them, generating diff output for easy future displaying (like side-by-side view) and so on.

Main reason to build this library was the lack of easy-to-use libraries with all the usual stuff you need while working with diff files. Originally it was inspired by JRCS library and it's nice design of diff module.

Main Features

  • computing the difference between two texts.
  • capable to hand more than plain ascci. Arrays or List of any type that implements hashCode() and equals() correctly can be subject to differencing using this library
  • patch and unpatch the text with the given patch
  • parsing the unified diff format
  • producing human-readable differences

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

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

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

主要特点

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

回答by Ravi K

You can use Apache Commons Textlibrary to achieve this. This library provides 'diff' capability based on "very efficient algorithm from Eugene W. Myers".

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

This provides you ability to create your own visitor so that you can process the diff in the way you want & may be output to console or HTML etc. Here is one article which walks through nice & simple example to output side by side diff in HTML formatusing Apache Commons Text library & simple Java code.

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