【问题标题】:How to diff parts of lines?如何区分部分行?
【发布时间】:2013-01-14 20:55:10
【问题描述】:

我有两个要比较的文件。这些行有时间戳,可能还有一些我想在匹配算法中忽略的其他内容,但是如果匹配算法在文本的其余部分发现差异,我仍然希望输出这些项目。例如:

1c1
<    [junit4] 2013-01-11 04:43:57,392 INFO  com.example.MyClass:123 [main] [loadOverridePropFile] Config file application.properties not found: java.io.FileNotFoundException: /path/to/application.properties (No such file or directory)
---
>    [junit4] 2013-01-11 22:16:07,398 INFO  com.example.MyClass:123 [main] [loadOverridePropFile] Config file application.properties not found: java.io.FileNotFoundException: /path/to/application.properties (No such file or directory)

不应该发出但是:

1c1
<    [junit4] 2013-01-11 04:43:57,392 INFO  com.example.MyClass:123 [main] [loadOverridePropFile] Config file application.properties not found: java.io.FileNotFoundException: /path/to/application.properties (No such file or directory)
---
>    [junit4] 2013-01-11 22:16:07,398 INFO  com.example.MyClass:456 [main] [loadOverridePropFile] Config file application.properties not found: java.io.FileNotFoundException: /path/to/application.properties (No such file or directory)

应该发出(因为行号不同)。请注意,仍会发出时间戳。

如何做到这一点?

【问题讨论】:

  • 一种方法是删除您不想匹配的信息,并仅使用相关数据制作文件的截断副本。但是,您必须保留准确的行号。然后您使用行号返回到您想要的文件并完整获取相关行。

标签: shell


【解决方案1】:

我希望这个功能在我之前好几次,因为它再次出现在这里,我决定用谷歌搜索一下,发现 perl 的 Algorithm::Diff 可以提供一个散列函数(他们称之为“密钥生成函数” ") 其中“应该返回一个唯一标识给定元素的字符串”,算法使用该字符串进行比较(而不是您提供给它的实际内容)。

基本上,您需要做的就是添加一个 sub 来执行一些正则表达式魔术,以便您希望从字符串中过滤掉不需要的内容,并将 subref 作为参数添加到对 diff() 的调用中(请参阅我的 @ 987654323@ 和 CHANGE 2 cmets 在下面的 sn-p 中)。

如果您需要正常(或统一)diff 输出,请检查模块附带的详细 diffnew.pl 示例,并在此文件中进行必要的更改。出于演示目的,我将使用它还附带的简单 diff.pl,因为它很短,我可以在这里完全发布。

mydiff.pl

#!/usr/bin/perl

# based on diff.pl that ships with Algorithm::Diff
# demonstrates the use of a key generation function

# the original diff.pl is:
# Copyright 1998 M-J. Dominus. (mjd-perl-diff@plover.com)
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.

use Algorithm::Diff qw(diff);

die("Usage: $0 file1 file2") unless @ARGV == 2;

my ($file1, $file2) = @ARGV;

-f $file1 or die("$file1: not a regular file");
-f $file2 or die("$file2: not a regular file");
-T $file1 or die("$file1: binary file");
-T $file2 or die("$file2: binary file");

open (F1, $file1) or die("Couldn't open $file1: $!");
open (F2, $file2) or die("Couldn't open $file2: $!");
chomp(@f1 = <F1>);
close F1;
chomp(@f2 = <F2>);
close F2;

# CHANGE 1
# $diffs = diff(\@f1, \@f2);
$diffs = diff(\@f1, \@f2, \&keyfunc);

exit 0 unless @$diffs;

foreach $chunk (@$diffs)
{
        foreach $line (@$chunk)
        {
                my ($sign, $lineno, $text) = @$line;
                printf "%4d$sign %s\n", $lineno+1, $text;
        }
}
exit 1;

# CHANGE 2 {
sub keyfunc
{
        my $_ = shift;
        s/^(\d{2}:\d{2})\s+//;
        return $_;
}
# }

one.txt

12:15 one two three
13:21 three four five

两个.txt

10:01 one two three
14:38 seven six eight

示例运行

$ ./mydiff.pl one.txt two.txt
   2- 13:21 three four five
   2+ 13:21 seven six eight

示例运行 2

这是一个基于diffnew.pl的正常diff输出

$ ./my_diffnew.pl one.txt two.txt
2c2
< 13:21 three four five
---
> 13:21 seven six eight

如您所见,两个文件中的第一行都会被忽略,因为它们只是时间戳不同,而散列函数会删除这些以进行比较。

瞧,你刚刚推出了自己的内容感知diff

【讨论】:

    【解决方案2】:

    假设您的文件是“a.txt”和“b.txt”。 您可以通过这种方式使用 diff + cut 获得它:

    diff <(cut -d" " -f4-99 a.txt) <(cut -d" " -f4-99 b.txt)
    

    每个剪切都会忽略前 3 个字段(与日期和这些内容相关),并且只考虑该行的其余部分(从第 4 列到第 99 列)。剪切应该使用:

    cut -d" " -f4- a.txt
    

    但它对我不起作用,所以我添加了 -f4-99。 因此,我们将 cut 应用于两个输入以忽略日期字段,然后我们运行 diff 以根据需要比较它们。

    【讨论】:

    • 这不是我想要的。我仍然希望输出时间戳;它们不应该被标记为不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 2015-06-21
    • 2020-08-03
    • 2013-03-23
    • 2010-11-08
    • 2023-03-18
    相关资源
    最近更新 更多