Java 查找Damerau Levenshtein编辑距离算法检测到的错误

Java 查找Damerau Levenshtein编辑距离算法检测到的错误,java,spell-checking,levenshtein-distance,edit-distance,damerau-levenshtein,Java,Spell Checking,Levenshtein Distance,Edit Distance,Damerau Levenshtein,我正在创建一个拼写纠正工具,并希望用贝叶斯定理实现一个嘈杂的通道。为了做到这一点,我需要计算概率P(X | W),其中X是给定的(拼写错误的)单词,W是可能的更正。概率是通过从混淆矩阵中获取一个值给出的,这取决于知道发生了哪种类型的错误,这意味着如果例如X=“egh”和W=“egg”,则编辑距离将为1,并且错误将是发生在字符号2上的替换错误 我正试图找到一种方法来获取错误“type”以及它发生的角色,但似乎无法使其正常工作。 我曾尝试创建一个树形图,并在检测到错误时插入I/j值,但没有成功 我可

我正在创建一个拼写纠正工具,并希望用贝叶斯定理实现一个嘈杂的通道。为了做到这一点,我需要计算概率P(X | W),其中X是给定的(拼写错误的)单词,W是可能的更正。概率是通过从混淆矩阵中获取一个值给出的,这取决于知道发生了哪种类型的错误,这意味着如果例如X=“egh”和W=“egg”,则编辑距离将为1,并且错误将是发生在字符号2上的替换错误

我正试图找到一种方法来获取错误“type”以及它发生的角色,但似乎无法使其正常工作。 我曾尝试创建一个树形图,并在检测到错误时插入I/j值,但没有成功

我可以假设只有一个错误,这意味着编辑距离正好是1

这是我的密码:

public static int DLD(String s1, String s2) {
    if (s1 == null || s2 == null) {  // Invalid input
        return -1;
    }

    if (s1.equals(s2)) {  // No distance to compute
        return 0;
    }

    // The max possible distance
    int inf = s1.length() + s2.length();

    // Create and initialize the character array indices
    HashMap<Character, Integer> da = new HashMap<>();
    for (int i = 0; i < s1.length(); ++i) {
        da.put(s1.charAt(i), 0);
    }
    for (int j = 0; j < s2.length(); ++j) {
        da.put(s2.charAt(j), 0);
    }

    // Create the distance matrix H[0 .. s1.length+1][0 .. s2.length+1]
    int[][] distances = new int[s1.length() + 2][s2.length() + 2];

    // initialize the left and top edges of H
    for (int i = 0; i <= s1.length(); ++i) {
        distances[i + 1][0] = inf;
        distances[i + 1][1] = i;
    }

    for (int j = 0; j <= s2.length(); ++j) {
        distances[0][j + 1] = inf;
        distances[1][j + 1] = j;

    }

    // fill in the distance matrix H
    // look at each character in s1
    for (int i = 1; i <= s1.length(); ++i) {
        int db = 0;

        // look at each character in s2
        for (int j = 1; j <= s2.length(); ++j) {
            int i1 = da.get(s2.charAt(j - 1));
            int j1 = db;

            int cost = 1;
            if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                cost = 0;
                db = j;
            }

            distances[i + 1][j + 1] = min(
                    distances[i][j] + cost, // substitution
                    distances[i + 1][j] + 1, // insertion
                    distances[i][j + 1] + 1, // deletion
                    distances[i1][j1] + (i - i1 - 1) + 1 + (j - j1 - 1));

        }

        da.put(s1.charAt(i - 1), i);
    }

    return distances[s1.length() + 1][s2.length() + 1];
}
publicstaticintdld(字符串s1、字符串s2){
如果(s1==null | | s2==null){//输入无效
返回-1;
}
如果(s1.等于(s2)){//无需计算距离
返回0;
}
//最大可能距离
int inf=s1.length()+s2.length();
//创建并初始化字符数组索引
HashMap da=新的HashMap();
对于(int i=0;i对于(int i=0;i而言,所涉及的错误类型和字符必须存储在某个位置。您可以将它们存储在单独的数据结构中,也可以将它们封装在对象中

下面是使用对象时可能出现的情况。为了简单起见,我只实现了Levenshtein距离,但我相信您可以轻松地将该技术应用到Damerau–Levenshtein

首先,您需要定义一个类来封装有关编辑的信息:成本、父项和任何额外信息,如类型(替换、插入、删除)或所涉及的字符对于此额外信息,您可能希望为错误类型、字符索引等添加单独的字段。您甚至可能希望使用继承创建具有不同行为的不同编辑子类型

class Edit implements Comparable<Edit> {
    int cost;
    Edit parent;
    String type;

    public Edit() {
        // create a "start" node with no parent and zero cost
    }

    public Edit(String type, Edit parent, int cost) {
        this.type = type;
        this.cost = parent.cost + cost;
        this.parent = parent;
    }

    @Override
    public int compareTo(Edit o) {
        return Integer.compare(this.cost, o.cost);
    }

    @Override
    public String toString() {
        return type;
    }
}
然后,“编辑距离”功能只需要计算最后一个节点的成本:

int editDistance(String s1, String s2) {
    Edit[][] distance = buildMatrix(s1, s2);
    return distance[s1.length()][s2.length()].cost;
}
但多亏了“父”指针,您还可以轻松构建将一个字符串更改为另一个字符串所需的编辑列表,也称为“差异”:

列表差异(字符串s1、字符串s2){
编辑[]距离=构建矩阵(s1,s2);
List diff=new ArrayList();
编辑=距离[s1.length()][s2.length()];
同时(编辑!=距离[0][0]){
差异添加(编辑);
edit=edit.parent;
}
集合。反向(差异);
返回差;
}

谢谢你的详细回答!我可能会尝试一下。我今天还记得,实际上可以回溯矩阵中的路径,因为这是一种动态规划算法,所以我也可以尝试一下。
Edit[][] buildMatrix(String s1, String s2) {
    Edit[][] distance = new Edit[s1.length() + 1][s2.length() + 1];

    distance[0][0] = new Edit();
    for (int i = 1; i <= s1.length(); i++) {
        distance[i][0] = new Edit("-" + s1.charAt(i - 1), distance[i - 1][0], 1);
    }
    for (int j = 1; j <= s2.length(); j++) {
        distance[0][j] = new Edit("+" + s2.charAt(j - 1), distance[0][j - 1], 1);
    }

    for (int i = 1; i <= s1.length(); i++) {
        for (int j = 1; j <= s2.length(); j++) {
            int replaceCost = s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1;
            distance[i][j] = Collections.min(List.of(
                // replace or same
                new Edit(s1.charAt(i - 1) + "/" + s2.charAt(j - 1), distance[i - 1][j - 1], replaceCost),
                // delete
                new Edit("-" + s1.charAt(i - 1), distance[i - 1][j], 1),
                // insert
                new Edit("+" + s2.charAt(j - 1), distance[i][j - 1], 1)));
        }
    }

    return distance;
}
int editDistance(String s1, String s2) {
    Edit[][] distance = buildMatrix(s1, s2);
    return distance[s1.length()][s2.length()].cost;
}
List<Edit> diff(String s1, String s2) {
    Edit[][] distance = buildMatrix(s1, s2);
    List<Edit> diff = new ArrayList<>();
    Edit edit = distance[s1.length()][s2.length()];
    while (edit != distance[0][0]) {
        diff.add(edit);
        edit = edit.parent;
    }
    Collections.reverse(diff);
    return diff;
}