Подтвердить что ты не робот

Библиотека Java для свободного текста diff

Мне нужно сопоставить две почти одинаковые длинные строки freetext; то есть находить соответствия индексов к индексу, где это возможно.

Поскольку это freetext, сравнение не должно быть линейным, как в случае кода.

Любые предложения для библиотек Java?

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

The quick brown  fox jumped over the  lazy     dog.
||||||||||      |||||||||||||||||||||         |||||
The quick yellow fox jumped over the well-bred dog.
4b9b3361

Ответ 1

Этот может быть хорошим Diff Match Patch. Другие?

Ответ 3

Здесь (слегка проверенная) версия кода, которая делает то, что вы просили. Вы можете легко пройти результат параллельно с входами, чтобы найти вставки и удаления.

public class StringDiff {

    private static int   length(String s) { return s == null ? 0 : s.length(); }
    private static char[] chars(String s) { return s == null ? new char[0] : s.toCharArray(); }

    private final String left;
    private final String right;

    private final char[] lccs;
    private final String lcs;

    public StringDiff(String left, String right) {
        this.left = left;
        this.right = right;
        lccs = init();
        lcs = new String(lccs);
    }

    public String getLcs()  { return lcs; }
    public char[] getLccs() { return lccs.clone(); }

    private char[] init() {
        int lLength = length(left);
        int rLength = length(right);
        char[] lChars = chars(left);
        char[] rChars = chars(right);
        int [][] t = new int [lLength + 1][rLength + 1];
        for (int i = lLength - 1; i >= 0; --i) {
            for (int j = rLength - 1; j >= 0; --j) {
                if (lChars[i] == rChars[j]) {
                    t[i][j] = t[i + 1][j + 1] + 1;
                } else {
                    t[i][j] = Math.max(t[i + 1][j], t[i][j + 1]);
                }
            }
        }
        char[] result = new char[t[0][0]];
        int l = 0, r = 0, p = 0;
        while (l < lLength && r < rLength) {
            if (lChars[l] == rChars[r]) {
                result[p++] = lChars[l++];
                r++;
            } else {
                if (t[l + 1][r] > t[l][r + 1]) {
                    ++l;
                } else {
                    ++r;
                }
            }
        }
        return result;
    }

}

В соответствии с этим, самая длинная подпоследовательность ваших исходных входов:

The quick brown  fox jumped over the  lazy     dog.
The quick yellow fox jumped over the well-bred dog.

является:

The quick ow fox jumped over the l dog.

(потому что "коричневый" и "желтый" имеют "общий" и т.д.)

Относительно просто изменить приведенное выше разделение на пробелы (вместо массивов char) и заменить String # equals for ==, чтобы получить версию, которая находит самую длинную общую подпоследовательность слов вместо символов. Для вашего примера выше это изменение приведет к очевидному результату:

found 7 words
    'The'
    'quick'
    'fox'
    'jumped'
    'over'
    'the'
    'dog.'

(Ваш вопрос подразумевает сравнение символов, поскольку вы сопоставляете пробелы между словами.)

Ответ 4

Если вы пример, это то, что вы хотите сделать, то есть подпоследовательности будут соответствовать только в том случае, если они начинаются с того же индекса (что отличается от того, как обычно работают различия) - это все, что вам нужно сделать:

import java.util.*;

class StringDiff {
    public static List<int[]> from(String s1, String s2) {
        int start = -1;
        int pos = 0;
        LinkedList<int[]> list = new LinkedList<int[]>();

        for(; pos < s1.length() && pos < s2.length(); ++pos) {
            if(s1.charAt(pos) == s2.charAt(pos)) {
                if(start < 0) start = pos;
            }
            else {
                if(start >= 0) list.add(new int[] { start, pos });
                start = -1;
            }
        }

        if(start >= 0) list.add(new int[] { start, pos });

        return list;
    }

    public static void main(String[] args) {
        for(int[] idx : from(args[0], args[1]))
            System.out.println(args[0].substring(idx[0], idx[1]));
    }
}

Реальная реализация diff будет намного более сложной.