使用emacs/python/winmerge在两个差异文件中映射行号
考虑下面这两个稍有不同的文件:
foo
(旧版本):
<Line 1> a
<Line 2> b
<Line 3> c
<Line 4> d
foo
(新版本):
<Line 1> a
<Line 2> e
<Line 3> b
<Line 4> c
<Line 5> f
<Line 6> d
你可以看到,在新文件中出现了字符 e
和 f
。
我有一组旧文件中的行号,比如 1
、3
和 4
(对应的字母是 a
、c
和 d
)。
有没有办法在这两个文件之间进行映射,这样我就能找到新文件中对应字符的行号呢?
比如,结果会是:
Old file line numbers (1,3,4) ===> New File line numbers (1,4,6)
不幸的是,我手头只有 emacs(带有可用的 ediff)、Python 和 winmerge。
2 个回答
3
你可以在Emacs这个编辑器里完成所有操作:
(defun get-joint-index (file-a index file-b)
(let ((table (make-hash-table :test #'equal)))
(flet ((line () (buffer-substring-no-properties
(point-at-bol) (point-at-eol))))
(with-temp-buffer (insert-file file-b)
(loop for i from 1 do (puthash (line) i table)
while (zerop (forward-line))))
(with-temp-buffer (insert-file file-a)
(loop for i in index do (goto-line i)
collect (gethash (line) table))))))
要运行这个代码,
M-:(get-joint-index "/tmp/old" '(1 3 4) "/tmp/new")
结果会是 (1 4 6)
2
你需要的是一种字符串搜索算法,这种算法可以让你在一段文本中查找多个模式(也就是旧版本foo中的那些行)。Rabin-Karp算法就是一种适合这种任务的算法。我已经把它调整为适合你的问题:
def linematcher(haystack, needles, lineNumbers):
f = open(needles)
needles = [line.strip() for n, line in enumerate(f, 1) if n in lineNumbers]
f.close()
hsubs = set(hash(s) for s in needles)
for n, lineWithNewline in enumerate(open(haystack), 1):
line = lineWithNewline.strip()
hs = hash(line)
if hs in hsubs and line in needles:
print "{0} ===> {1}".format(lineNumbers[needles.index(line)], n)
假设你的两个文件分别叫做old_foo.txt
和new_foo.txt
,那么你可以这样调用这个函数:
linematcher('new_foo.txt', 'old_foo.txt', [1, 3, 4])
当我在你的数据上试的时候,它输出了:
1 ===> 1
3 ===> 4
4 ===> 6