我需要匹配两个几乎相同的长自由文本字符串;即,尽可能找到索引到索引的对应关系。
因为这是自由文本,所以比较不应该像代码差异一样基于行。
对Java库有什么建议吗?
一个简单的例子(在现实生活中,当然,不会有额外的空格来排列,并且可能会有更复杂的挑战,比如整个条款的移动。)
The quick brown fox jumped over the lazy dog.
|||||||||| ||||||||||||||||||||| |||||
The quick yellow fox jumped over the well-bred dog.
答案 0 :(得分:16)
这个可能很好Diff Match Patch。
答案 1 :(得分:8)
根据您的具体要求,Apache Commons Lang组件的StringUtils
类可能会有所帮助,例如:
答案 2 :(得分:1)
这是一个(轻度测试的)代码版本,可以满足您的要求。您可以轻松地与输入并行遍历结果,以定位插入和删除。
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.
(因为“棕色”和“黄色”共有“ow”等)。
将上面的内容修改为空白(而不是成为char数组)并将String#equals替换为==以获取找到单词而不是字符的最长公共子序列的版本,这是相对简单的。对于上面的例子,这种改变会产生明显的结果:
found 7 words
'The'
'quick'
'fox'
'jumped'
'over'
'the'
'dog.'
(你的问题暗示了字符比较,因为你匹配单词之间的空格。)
答案 3 :(得分:0)
如果你的例子真的是你想做的事情 - 即子序列只有在相同的索引处开始时才会匹配(这与差异正常运行的方式不同) - 这就是你需要做的全部:
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]));
}
}
实际的差异实现会更加复杂。