diff

元の論文を読まずに、CやらRubyのソース辺をかき集めて動くように。

http://hp.vector.co.jp/authors/VA007799/viviProg/doc5.htm
http://raa.ruby-lang.org/search.rhtml?search=diff.rb

struct Diff_Result {
	int[][2] path;
}

Diff_Result diff(char[] data_a, char[] data_b)
{
	char[] A;
	char[] B;
	int[int] editgraph;
	
	Diff_Result create_path()
	{
		Diff_Result result;
		const int[1] zero = [0];
		int x = A.length; 
		int y = B.length;
		result.path[0] = (&x)[0..1].dup; 
		result.path[1] = (&y)[0..1].dup; 
		while(0 < x && 0 < y){
			int s = editgraph[x + y * B.length];
			if(s != 0){
				x -= s; 
				y -= s;
				result.path[0] ~= (&x)[0..1];
				result.path[1] ~= (&y)[0..1];
			}
			if((x + (y - 1) * B.length) in editgraph){
				do{
					--y;
				}while(0 < y && (x + (y - 1) * B.length) in editgraph);
				result.path[0] ~= (&x)[0..1]; 
				result.path[1] ~= (&y)[0..1]; 
			}
			if(((x - 1) + y * B.length) in editgraph){
				do{
					--x;
				}while(0 < x && ((x - 1) + y * B.length) in editgraph);
				result.path[0] ~= (&x)[0..1];
				result.path[1] ~= (&y)[0..1];
			}
		}
		if(result.path[0][result.path[0].length - 1] != 0 ||
			result.path[1][result.path[1].length - 1] != 0)
		{
			result.path[0] ~= zero;
			result.path[1] ~= zero;
		}
		result.path[0] = result.path[0].reverse;
		result.path[1] = result.path[1].reverse;
		return result;
	}
	
	int snake(int k, int fpa, int fpb)
	{
		int y = (fpa > fpb) ? fpa : fpb;
		int x = y - k;
		int M = A.length;
		int N = B.length;
		int count = 0;
		//printf("%d, %d"\n, x, y);
		while(x < M && y < N && A[x] == B[y]){
			++x;
			++y;
			++count;
		}
		editgraph[x + y * B.length] = count;
		return y;
	}

	if(data_a.length <= data_b.length){
		A = data_a;
		B = data_b;
	}else{
		A = data_b;
		B = data_a;
	}
	
	int M = A.length;
	int N = B.length;
	int[] fp;
	fp.length = M + N + 3;
	fp[0..fp.length] = -1;
	int offset = M + 1;
	int DELTA = N - M;
	assert(DELTA >= 0);
	for(int p = 0; p <= M; ++p){
		for(int k = -p; k < DELTA; ++k)
			fp[k + offset] = snake(k, fp[k-1+offset] + 1, fp[k+1+offset]);
		for(int k = DELTA + p; k >= DELTA; --k)
			fp[k + offset] = snake(k, fp[k-1+offset] + 1, fp[k+1+offset]);
		//printf("%d %d\n", fp[DELTA + offset], N);
		if(fp[DELTA + offset] == N)
		{
			Diff_Result result = create_path();
			if(data_a.length > data_b.length){
				int[] t = result.path[0];
				result.path[0] = result.path[1];
				result.path[1] = t;
			}
			return result;
		}
	}
	assert(false);
}

int main()
{
	char[] A = "ABCDEF";
	char[] B = "AB---CDEF";
	
	Diff_Result r = diff(A, B);
	for(int i = 0; i < r.path[0].length; ++i){
		printf("%d ", r.path[0][i]);
	}
	printf("\n");
	for(int i = 0; i < r.path[1].length; ++i){
		printf("%d ", r.path[1][i]);
	}
	
	return 0;
}
0 2 2 6
0 2 5 9

Thebeにバイナリ比較コマンドを実装するのに使おう。
それと、今さらながらに、静的配列って返せないんですね…。無駄にstructでラップが必要に…。