src/main/java/eu/digitisation/distance/StringEditDistance.java
public static BiCounter<Character, EdOp> operations(String first, String second) {
        int i, j;
        int[][] A;
        EditTable B;
        BiCounter<Character, EdOp> stats = new BiCounter<Character, EdOp>();

        // intialize
        A = new int[2][second.length() + 1];
        B = new EditTable(first.length() + 1, second.length() + 1);
        // Compute first row
        A[0][0] = 0;
        B.set(0, 0, EdOp.KEEP);
        for (j = 1; j <= second.length(); ++j) {
            A[0][j] = A[0][j - 1] + 1;
            B.set(0, j, EdOp.INSERT);
        }

        // Compute other rows
        for (i = 1; i <= first.length(); ++i) {
            A[i % 2][0] = A[(i - 1) % 2][0] + 1;
            B.set(i, 0, EdOp.DELETE);
            for (j = 1; j <= second.length(); ++j) {
                if (first.charAt(i - 1) == second.charAt(j - 1)) {
                    A[i % 2][j] = A[(i - 1) % 2][j - 1];
                    B.set(i, j, EdOp.KEEP);
                } else {
                    A[i % 2][j] = min(A[(i - 1) % 2][j] + 1,
                            A[i % 2][j - 1] + 1,
                            A[(i - 1) % 2][j - 1] + 1);
                    if (A[i % 2][j] == A[(i - 1) % 2][j] + 1) {
                        B.set(i, j, EdOp.DELETE);
                    } else if (A[i % 2][j] == A[i % 2][j - 1] + 1) {
                        B.set(i, j, EdOp.INSERT);
                    } else {
                        B.set(i, j, EdOp.SUBSTITUTE);
                    }
                }
            }
        }

        i = first.length();
        j = second.length();
        while (i > 0 && j > 0) {
            switch (B.get(i, j)) {
                case KEEP:
                    stats.inc(first.charAt(i - 1), EdOp.KEEP);
                    --i;
                    --j;
                    break;
                case DELETE:
                    stats.inc(first.charAt(i - 1), EdOp.DELETE);
                    --i;
                    break;
                case INSERT:
                    stats.inc(second.charAt(j - 1), EdOp.INSERT);
                    --j;
                    break;
                case SUBSTITUTE:
                    stats.inc(first.charAt(i - 1), EdOp.SUBSTITUTE);

                    --i;
                    --j;
                    break;
            }
        }
        while (i > 0) {
            stats.inc(first.charAt(i - 1), EdOp.DELETE);
            --i;
        }
        while (j > 0) {
            stats.inc(second.charAt(j - 1), EdOp.INSERT);
            --j;

        }

        return stats;
    }
/**
     * Computes the number of edit operations per character
     *
     * @param first the reference text
     * @param second the fuzzy text
     * @return a counter with the number of insertions, substitutions and
     * deletions for every character
     */
Computes the number of edit operations per character
@param first the reference text
@param second the fuzzy text
@return a counter with the number of insertions, substitutions and
deletions for every character
Computes the number of edit operations per character @param first the reference text @param second the fuzzy text @return a counter with the number of insertions substitutions and deletions for every character
public static BiCounter<Character, EdOp> operations(String first, String second) {
        int i, j;
        int[][] A;
        EditTable B;
        BiCounter<Character, EdOp> stats = new BiCounter<Character, EdOp>();
        A = new int[2][second.length() + 1];
        B = new EditTable(first.length() + 1, second.length() + 1);
        A[0][0] = 0;
        B.set(0, 0, EdOp.KEEP);
        for (j = 1; j <= second.length(); ++j) {
            A[0][j] = A[0][j - 1] + 1;
            B.set(0, j, EdOp.INSERT);
        }
        for (i = 1; i <= first.length(); ++i) {
            A[i % 2][0] = A[(i - 1) % 2][0] + 1;
            B.set(i, 0, EdOp.DELETE);
            for (j = 1; j <= second.length(); ++j) {
                if (first.charAt(i - 1) == second.charAt(j - 1)) {
                    A[i % 2][j] = A[(i - 1) % 2][j - 1];
                    B.set(i, j, EdOp.KEEP);
                } else {
                    A[i % 2][j] = min(A[(i - 1) % 2][j] + 1,
                            A[i % 2][j - 1] + 1,
                            A[(i - 1) % 2][j - 1] + 1);
                    if (A[i % 2][j] == A[(i - 1) % 2][j] + 1) {
                        B.set(i, j, EdOp.DELETE);
                    } else if (A[i % 2][j] == A[i % 2][j - 1] + 1) {
                        B.set(i, j, EdOp.INSERT);
                    } else {
                        B.set(i, j, EdOp.SUBSTITUTE);
                    }
                }
            }
        }
        i = first.length();
        j = second.length();
        while (i > 0 && j > 0) {
            switch (B.get(i, j)) {
                case KEEP:
                    stats.inc(first.charAt(i - 1), EdOp.KEEP);
                    --i;
                    --j;
                    break;
                case DELETE:
                    stats.inc(first.charAt(i - 1), EdOp.DELETE);
                    --i;
                    break;
                case INSERT:
                    stats.inc(second.charAt(j - 1), EdOp.INSERT);
                    --j;
                    break;
                case SUBSTITUTE:
                    stats.inc(first.charAt(i - 1), EdOp.SUBSTITUTE);
                    --i;
                    --j;
                    break;
            }
        }
        while (i > 0) {
            stats.inc(first.charAt(i - 1), EdOp.DELETE);
            --i;
        }
        while (j > 0) {
            stats.inc(second.charAt(j - 1), EdOp.INSERT);
            --j;
        }
        return stats;
    }
public static BiCounter < Character , EdOp > operations ( String first , String second ) { int i , j ; int [ ] [ ] A ; EditTable B ; BiCounter < Character , EdOp > stats = new BiCounter < Character , EdOp > ( ) ; A = new int [ 2 ] [ second . length ( ) + 1 ] ; B = new EditTable ( first . length ( ) + 1 , second . length ( ) + 1 ) ; A [ 0 ] [ 0 ] = 0 ; B . set ( 0 , 0 , EdOp . KEEP ) ; for ( j = 1 ; j <= second . length ( ) ; ++ j ) { A [ 0 ] [ j ] = A [ 0 ] [ j - 1 ] + 1 ; B . set ( 0 , j , EdOp . INSERT ) ; } for ( i = 1 ; i <= first . length ( ) ; ++ i ) { A [ i % 2 ] [ 0 ] = A [ ( i - 1 ) % 2 ] [ 0 ] + 1 ; B . set ( i , 0 , EdOp . DELETE ) ; for ( j = 1 ; j <= second . length ( ) ; ++ j ) { if ( first . charAt ( i - 1 ) == second . charAt ( j - 1 ) ) { A [ i % 2 ] [ j ] = A [ ( i - 1 ) % 2 ] [ j - 1 ] ; B . set ( i , j , EdOp . KEEP ) ; } else { A [ i % 2 ] [ j ] = min ( A [ ( i - 1 ) % 2 ] [ j ] + 1 , A [ i % 2 ] [ j - 1 ] + 1 , A [ ( i - 1 ) % 2 ] [ j - 1 ] + 1 ) ; if ( A [ i % 2 ] [ j ] == A [ ( i - 1 ) % 2 ] [ j ] + 1 ) { B . set ( i , j , EdOp . DELETE ) ; } else if ( A [ i % 2 ] [ j ] == A [ i % 2 ] [ j - 1 ] + 1 ) { B . set ( i , j , EdOp . INSERT ) ; } else { B . set ( i , j , EdOp . SUBSTITUTE ) ; } } } } i = first . length ( ) ; j = second . length ( ) ; while ( i > 0 && j > 0 ) { switch ( B . get ( i , j ) ) { case KEEP : stats . inc ( first . charAt ( i - 1 ) , EdOp . KEEP ) ; -- i ; -- j ; break ; case DELETE : stats . inc ( first . charAt ( i - 1 ) , EdOp . DELETE ) ; -- i ; break ; case INSERT : stats . inc ( second . charAt ( j - 1 ) , EdOp . INSERT ) ; -- j ; break ; case SUBSTITUTE : stats . inc ( first . charAt ( i - 1 ) , EdOp . SUBSTITUTE ) ; -- i ; -- j ; break ; } } while ( i > 0 ) { stats . inc ( first . charAt ( i - 1 ) , EdOp . DELETE ) ; -- i ; } while ( j > 0 ) { stats . inc ( second . charAt ( j - 1 ) , EdOp . INSERT ) ; -- j ; } return stats ; }
Computes the number of edit operations per character
 @param first the reference text
 @param second the fuzzy text
 @return a counter with the number of insertions, substitutions and
 deletions for every character
Computes the number of edit operations per character @param first the reference text @param second the fuzzy text @return a counter with the number of insertions substitutions and deletions for every character
// intialize // Compute first row // Compute other rows