使用“diff”(或其他任何东西)来获取文本文件之间的字符级差异

Posted

技术标签:

【中文标题】使用“diff”(或其他任何东西)来获取文本文件之间的字符级差异【英文标题】:Using 'diff' (or anything else) to get character-level diff between text files 【发布时间】:2010-12-15 20:34:32 【问题描述】:

我想使用 'diff' 来获得两者之间的行差异和字符差异。 例如,考虑:

文件 1

abcde
abc
abcccd

文件 2

abcde
ab
abccc

使用 diff -u 我得到:

@@ -1,3 +1,3 @@
 abcde
-abc
-abcccd
\ No newline at end of file
+ab
+abccc
\ No newline at end of file

但是,它只向我展示了这些行的变化。我想看到的是这样的:

@@ -1,3 +1,3 @@
 abcde
-ab<ins>c</ins>
-abccc<ins>d</ins>
\ No newline at end of file
+ab
+abccc
\ No newline at end of file

你明白我的意思。

现在,我知道我可以使用other engines 来标记/检查特定行的差异。但我宁愿使用一种工具来完成所有工作。

【问题讨论】:

per char diff 在涉及 CJK 文本时特别有用,其中没有空格用于分词。 【参考方案1】:

Git 有一个单词 diff,将所有字符定义为单词有效地为您提供了一个字符 diff。但是,换行符更改被忽略

示例

像这样创建一个存储库:

mkdir chardifftest
cd chardifftest
git init
echo -e 'foobarbaz\ncatdog\nfox' > file
git add -A; git commit -m 1
echo -e 'fuobArbas\ncat\ndogfox' > file
git add -A; git commit -m 2

现在,执行git diff --word-diff=color --word-diff-regex=. master^ master,您将获得:

请注意如何在字符级别识别添加和删除,而忽略换行符的添加和删除。

您可能还想尝试以下方法之一:

git diff --word-diff=plain --word-diff-regex=. master^ master
git diff --word-diff=porcelain --word-diff-regex=. master^ master

【讨论】:

你根本不需要创建一个仓库,你可以简单地在你的文件系统的任何地方给 git diff 任意两个文件,它就可以工作了。你的命令以这种方式对我很有用,所以谢谢! git diff --word-diff=color --word-diff-regex=. file1 file2 这非常有帮助!如果可以的话,我会作为软件开发人员 +1 一次,作为作者/作家 +1 两次。与代码中的行往往相当短的情况不同,在编写论文/故事时,每个段落都倾向于采用长的自动换行的形式,并且此功能使差异实际上在视觉上很有用。 我需要在上面添加 --no-index 到@qwertzguys 的回复,以便让它在 git repo 之外为我工作。所以:git diff --no-index --word-diff=color --word-diff-regex=. file1 file2 git diff 在一般设置中不起作用:git diff --no-index --word-diff=color --word-diff-regex=。 @NathanBell 我也需要在仓库中添加--no-index【参考方案2】:

你可以使用:

diff -u f1 f2 |colordiff |diff-highlight

colordiff 是一个 Ubuntu 软件包。您可以使用sudo apt-get install colordiff 安装它。

diff-highlight 来自 git(从 2.9 版开始)。它位于/usr/share/doc/git/contrib/diff-highlight/diff-highlight。你可以把它放在你的$PATH中的某个地方。

【讨论】:

colordiff 也可用于 Mac 的自制软件:brew install colordiff 在 Mac 上,您可以在 $(brew --prefix git)/share/git-core/contrib/diff-highlight/diff-highlight 中找到 diff-highlight 如果您没有使用 brew 安装 git - diff-highlight 也可以使用 python 的 pip 安装 - pip install diff-highlight (即使通过 brew 安装 git 我也更喜欢它) 你实际上可以跳过第一个差异步骤,因为它的价值 colordiff -u file1 file2 | diff-highlight 对我有用 太棒了,正是我所需要的。【参考方案3】:

如果您想以编程方式执行此操作,Python 的difflib 是王牌。对于交互使用,我使用vim's diff 模式(很容易使用:只需使用vimdiff a b 调用vim)。我也偶尔使用Beyond Compare,它几乎可以满足您对差异工具的所有期望。

我没有看到任何有用的命令行工具,但正如 Will 所说,difflib 示例代码可能会有所帮助。

【讨论】:

哦.. 我希望有一个更标准化的东西(比如隐藏的命令行参数)。最糟糕的是,我有 Beyond Compare 2,它甚至支持将文本输出到 diff 的文件/控制台,但它仍然只包括 line-diffs 而不是 char-diffs。如果没有人有其他东西,我会研究python。 +1 向我介绍了 vimdiff。我发现默认颜色不可读,但在 ***.com/questions/2019281/… 找到了解决方案。【参考方案4】:

您可以在 Solaris 中使用cmp 命令:

cmp

比较两个文件,如果不同,告诉第一个字节和行号它们不同的地方。

【讨论】:

cmp 也可用于(至少某些)Linux 发行版。 Mac OS X 上也可以使用。 字符可以由多个字节组成,OP 要求进行视觉比较。 @CeesTimmerman:cmp 允许视觉比较,带有标志-l -b【参考方案5】:

Python 有一个名为 difflib 的便捷库,它可能有助于回答您的问题。

下面是两个使用difflib 的单行器,用于不同的python 版本。

python3 -c 'import difflib, sys; \
  print("".join( \
    difflib.ndiff( \ 
      open(sys.argv[1]).readlines(),open(sys.argv[2]).readlines())))'
python2 -c 'import difflib, sys; \
  print "".join( \
    difflib.ndiff( \
      open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines()))'

这些可能会作为 shell 别名派上用场,它更容易与您的 .$SHELL_NAMErc 一起移动。

$ alias char_diff="python2 -c 'import difflib, sys; print \"\".join(difflib.ndiff(open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines()))'"
$ char_diff old_file new_file

还有更易读的版本放入独立文件中。

#!/usr/bin/env python2
from __future__ import with_statement

import difflib
import sys

with open(sys.argv[1]) as old_f, open(sys.argv[2]) as new_f:
    old_lines, new_lines = old_f.readlines(), new_f.readlines()
diff = difflib.ndiff(old_lines, new_lines)
print ''.join(diff)

【讨论】:

优秀的一个衬里。有一个忽略未更改行的压缩输出会很好。【参考方案6】:
cmp -l file1 file2 | wc

对我来说效果很好。结果最左边的数字表示不同的字符数。

【讨论】:

或者只获取最左边的数字:cmp -l file1 file2 | wc -l【参考方案7】:

我还写了我的own script 来解决这个问题,使用Longest common subsequence algorithm.

就这样执行

JLDiff.py a.txt b.txt out.html

结果是带有红色和绿色的 html。较大的文件确实需要更长的时间来处理,但这会进行真正的逐字符比较,而无需先逐行检查。

【讨论】:

我发现JLDiff在pypy下跑得快了很多。【参考方案8】:

彩色,字符级 diff 输出

您可以使用以下脚本和diff-highlight(它是 git 的一部分)来执行以下操作:

#!/bin/sh -eu

# Use diff-highlight to show word-level differences

diff -U3 --minimal "$@" |
  sed 's/^-/\x1b[1;31m-/;s/^+/\x1b[1;32m+/;s/^@/\x1b[1;34m@/;s/$/\x1b[0m/' |
  diff-highlight

(感谢@retracile's answer 突出显示sed

【讨论】:

它在 shell 屏幕上显示了很好的差异,但我如何在 GVim 中看到差异?? 这是一个真正的 gvim 问题 :)。 command | gvim - 会做你想做的事。 供参考 diff-highlight 似乎包含在git 的一部分中,但没有放在您的路径上。我的一台机器住在/usr/share/doc/git/contrib/diff-highlight 链接断开。如何安装差异突出显示。似乎不在包管理器中。【参考方案9】:

Python 的 difflib 可以做到这一点。

文档包含一个示例 command-line program 供您使用。

确切的格式与您指定的不同,但解析 ndiff 样式的输出或修改示例程序以生成您的符号会很简单。

【讨论】:

谢谢!我会调查的。我希望有一个更标准化的东西(比如隐藏的命令行参数)。但它可能仍然做得很好。如果没有人有更标准的东西,我会研究 python(尽管看起来没有)。【参考方案10】:

这是一个在线文本比较工具: http://text-compare.com/

它可以突出显示每个不同的字符并继续比较其余字符。

【讨论】:

这似乎做了行级差异,没有单个字符的选项。你如何得到它来比较字符? 啊;它突出显示不同的字符。但它仍然是行级的,catdogcat\ndog 只会匹配 cat【参考方案11】:

我认为更简单的解决方案始终是一个好的解决方案。 就我而言,下面的代码对我有很大帮助。我希望它有帮助 其他人。

#!/bin/env python

def readfile( fileName ):
    f = open( fileName )
    c = f.read()
    f.close()
    return c

def diff( s1, s2 ):
    counter=0
    for ch1, ch2 in zip( s1, s2 ):
        if not ch1 == ch2:
            break
        counter+=1
    return counter < len( s1 ) and counter or -1

import sys

f1 = readfile( sys.argv[1] )
f2 = readfile( sys.argv[2] )
pos = diff( f1, f2 )
end = pos+200

if pos >= 0:
    print "Different at:", pos
    print ">", f1[pos:end]
    print "<", f2[pos:end]

您可以在您喜欢的终端上使用以下语法比较两个文件:

$ ./diff.py fileNumber1 fileNumber2

【讨论】:

【参考方案12】:

如果您将文件保存在 Git 中,则可以使用 diff-highlight script 区分版本,这将显示不同的行,并突出显示差异。

不幸的是,它仅在删除的行数与添加的行数匹配时才有效 - 当行不匹配时存在存根代码,因此可能会在将来修复此问题。

【讨论】:

【参考方案13】:

不是一个完整的答案,但是如果cmp -l的输出不够清晰,可以使用:

sed 's/\(.\)/\1\n/g' file1 > file1.vertical
sed 's/\(.\)/\1\n/g' file2 > file2.vertical
diff file1.vertical file2.vertical

【讨论】:

在 OSX 上使用 ``` sed 's/(.)/\1\'$'\n/g' file1 > file1.vertical sed 's/\(.\)/\1 \'$'\n/g' file2 > file2.vertical ```【参考方案14】:

这些答案中的大多数都提到了使用 Perl 模块 diff-highlight。但我不想弄清楚如何安装 Perl 模块。因此,我对其进行了一些小改动,使其成为一个独立的 Perl 脚本。

您可以使用以下方式安装它:

▶ curl -o /usr/local/bin/DiffHighlight.pl \
   https://raw.githubusercontent.com/alexharv074/scripts/master/DiffHighlight.pl

以及用法(如果你有 zhanxw 的回答中提到的 Ubuntu colordiff):

▶ diff -u f1 f2 | colordiff | DiffHighlight.pl

以及用法(如果你不这样做):

▶ diff -u f1 f2 | DiffHighlight.pl

【讨论】:

【参考方案15】:

ccdiff 是一个方便的专用工具。这是您的示例的样子:

默认情况下,它会突出显示颜色的差异,但也可以在不支持颜色的控制台中使用。

包包含在main repository of Debian:

ccdiff 是一个彩色差异,它也在改变的行内着色。

所有显示两个文件之间差异的命令行工具都无法显示明显有用的微小更改。 ccdiff 尝试提供diff --colorcolordiff 的外观和感觉,但将彩色输出的显示从已删除和添加的彩色行扩展到更改行中已删除和添加的字符的颜色。

【讨论】:

看起来不错,但缺少非 Debian 系统的正确安装说明。

以上是关于使用“diff”(或其他任何东西)来获取文本文件之间的字符级差异的主要内容,如果未能解决你的问题,请参考以下文章

Linux基本命令之diff

Linux-diff --比较两个文件并输出不同之处

diff命令

Android - 从图像中裁剪文本(使用 openCV 或其他任何东西)

使用 PCA 或类似的东西从文本文件中获取集群分配的可视化?

linux下比较两个文本文件的不同——diff命令