Сравнение файлов с подсветкой изменений

Для CVS необходимо показывать в документе разницу между двумя файлами. Файлы представляют собой html документы. Пользователю нужно показывать изменения в тексте, а не в коде.

Наиболее подходящий вариант это скрипт написанный на основе difflib python.

Diff.php

< ?php
 
 
/**
 * File:        Diff.php
 * Description: Compare string or files class
 
*/
 
 
 
class Cvs_Diff
{
 
 
	protected  $python_path ='/usr/local/bin/python';
	protected  $diff_path ='/usr/local/www/data/dev/library/Cvs/diff.py';
 
 
 
	function __construct()
	{
 
		if(!file_exists($this->python_path))
			throw new Zend_Exception('python not found:'.$this->python_path);	
 
		if(!file_exists($this->diff_path))
			throw new Zend_Exception('diff python not found:'.$this->diff_path);	
 
	}
 
 
	/**
	 * Show difference between  two files with HTML highlight
	 *
	 * @param string $file_a first file for compare
	 * @param string $file_b second file for compare
	 * @return string HTML out put
	 */
	public function files($file_a, $file_b)
	{
 
		if(!file_exists($file_a))
			throw new Zend_Exception('file A not found :'.$file_a);
		if(!file_exists($file_b))
			throw new Zend_Exception('file B not found :'.$file_b);
 
		$output = shell_exec("$this->python_path $this->diff_path  $file_a $file_b");
		$output .= '<style type="text/css"><!-- ins {background: #bfb} del{background: #fcc} ins,del {text-decoration: none} --></style>';
		return 		$output;
	}
 
 
	/**
	 * Show difference between  two strings with HTML highlight
	 *
	 * @param string $str_a
	 * @param string $str_b
	 * @return string HTML out put
	 */
 
 
	public function string($str_a, $str_b)
	{
 
		$tmpfname_a = tempnam("/tmp", "diff_");
		$tmpfname_b = tempnam("/tmp", "diff_");
 
		if(!file_put_contents($tmpfname_a,$str_a))
			throw new Zend_Exception('can\'t create temporary file :'.$tmpfname_a);
 
		if(!file_put_contents($tmpfname_b,$str_b))
			throw new Zend_Exception('can\'t create temporary file :'.$tmpfname_b);
 
 
		$output = shell_exec("$this->python_path $this->diff_path  $tmpfname_a $tmpfname_b");
 
		unlink($tmpfname_a);
		unlink($tmpfname_b);
		$output .= '<style type="text/css"><!-- ins {background: #bfb} del{background: #fcc} ins,del {text-decoration: none} --></style>';
		return 		$output;
	}
 
 
 
 
}

diff.py

 
#!/usr/bin/python
"""HTML Diff: http://www.aaronsw.com/2002/diff
Rough code, badly documented. Send me comments and patches."""
 
 
__author__ = 'Aaron Swartz <me @aaronsw.com>'
__copyright__ = '(C) 2003 Aaron Swartz. GNU GPL 2.'
__version__ = '0.22'
 
import difflib, string
 
def isTag(x): return x[0] == "< " and x[-1] == ">"
 
def textDiff(a, b):
	"""Takes in strings a and b and returns a human-readable HTML diff."""
 
	out = []
	a, b = html2list(a), html2list(b)
	s = difflib.SequenceMatcher(None, a, b)
	for e in s.get_opcodes():
		if e[0] == "replace":
			# @@ need to do something more complicated here
			# call textDiff but not for html, but for some html... ugh
			# gonna cop-out for now
			out.append('<del class="diff modified">'+''.join(a[e[1]:e[2]]) + '</del><ins class="diff modified">'+''.join(b[e[3]:e[4]])+"</ins>")
		elif e[0] == "delete":
			out.append('<del class="diff">'+ ''.join(a[e[1]:e[2]]) + "</del>")
		elif e[0] == "insert":
			out.append('<ins class="diff">'+''.join(b[e[3]:e[4]]) + "</ins>")
		elif e[0] == "equal":
			out.append(''.join(b[e[3]:e[4]]))
		else: 
			raise "Um, something's broken. I didn't expect a '" + `e[0]` + "'."
	return ''.join(out)
 
def html2list(x, b=0):
	mode = 'char'
	cur = ''
	out = []
	for c in x:
		if mode == 'tag':
			if c == '>': 
				if b: cur += ']'
				else: cur += c
				out.append(cur); cur = ''; mode = 'char'
			else: cur += c
		elif mode == 'char':
			if c == '< ': 
				out.append(cur)
				if b: cur = '['
				else: cur = c
				mode = 'tag'
			elif c in string.whitespace: out.append(cur+c); cur = ''
			else: cur += c
	out.append(cur)
	return filter(lambda x: x is not '', out)
 
if __name__ == '__main__':
	import sys
	try:
		a, b = sys.argv[1:3]
	except ValueError:
		print "htmldiff: highlight the differences between two html files"
		print "usage: " + sys.argv[0] + " a b"
		sys.exit(1)
	print textDiff(open(a).read(), open(b).read())

Получать новые сообщения по Email

Оставить комментарий