免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5396 | 回复: 8
打印 上一主题 下一主题

求助:如何提取两个文本中相同的行,存入另一个新文本。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-03-03 12:14 |只看该作者 |倒序浏览
      网上翻,论坛找,都未找到多文本提取相同行的例子,好像全世界都很讨厌重复行,要删除它都是些去重复的例子,郁闷!正在啃perl 5,希望各位大侠指点下,写个提取两个文本中相同的行,存入另一个新文本的代码的示例,帮助新手学习,能注释一下就更完美了,谢谢大家啦!

我需要的示例要求如下:

   提取1.txt与2.txt中相同行保存为3.txt

文本文件;1.txt(需要查重的文件)
01 02 03 04 05 06
02 03 04 05 06 07
15 19 22 24 27 28 33 36
01 09 14 15 19 23


文本文件;2.txt(内容比较多的文件)
01 02 03 04 05 06
02 03 04 05 06 07
05 06 07 08 09 10 11
03 04 05 06 07 08
05 07 09 11 13 14 15
08 10 14 15 17 22 23 25
11 12 16 18 19 41
22 24 29 34 37 39

文本文件;3.txt (需要的结果)
01 02 03 04 05 06
02 03 04 05 06 07

论坛徽章:
1
CU大牛徽章
日期:2013-03-14 14:08:55
2 [报告]
发表于 2013-03-03 13:45 |只看该作者
看看这样吧, 核心只有一句 grep {   grep {} ....  } ... 的判断
  1. #! /usr/bin/perl

  2. use strict;
  3. use warnings;

  4. my $src_lines_1_ref = get_lines_from_file('1.txt');
  5. my $src_lines_2_ref = get_lines_from_file('2.txt');
  6. my @dst_lines = grep {
  7.     my $line = $_;                                             
  8.     grep $_ eq $line, @$src_lines_1_ref;
  9. } @$src_lines_2_ref;
  10. write_lines_to_file('3.txt', \@dst_lines);

  11. sub get_lines_from_file {
  12.     my $file = shift || "";
  13.     my @lines;
  14.     open my $FILE, "<$file" or die "Cannot open $file: $!";
  15.     while (<$FILE>) {
  16.         chomp;      
  17.         next if /^\s*$/ #删除空行
  18.         s/^\s*//;           # 注释掉行头的空格
  19.         s/\s*$//;           # 注释掉行尾的空格
  20.         push @lines, $_;
  21.     }
  22.     close $FILE;
  23.     return \@lines;
  24. }

  25. sub write_lines_to_file {
  26.     my $file = shift || "";
  27.     my $lines_ref = shift || "";
  28.     open my $FILE, ">$file" or die "Cannot open $file: $!";
  29.     for (@$lines_ref) {
  30.         print $FILE $_."\n";
  31.     }
  32.     close $FILE;
  33. }
复制代码

论坛徽章:
1
天蝎座
日期:2013-11-25 10:40:37
3 [报告]
发表于 2013-03-03 13:59 |只看该作者
  1. #!/usr/bin perl
  2. use v5.14;
  3. use warnings;
  4. use autodie;

  5. open(my $a_fd, '<', 'a.txt');
  6. open(my $b_fd, '<', 'b.txt');

  7. #output file
  8. open(my $c_fd, '>', 'c.txt');
  9. my %lines_in_a;

  10. while (<$a_fd>) {
  11.     chomp;
  12.     #将a文件中的所有行加入map中
  13.     $lines_in_a{$_} = 1;
  14. }

  15. while (<$b_fd>) {
  16.     chomp;
  17.     #如果发现b.txt中有行与a.txt中相同则认为重复,并输入到c.txt中
  18.     if (exists($lines_in_a{$_})) {
  19.         say {$c_fd} $_;
  20.     }
  21. }

  22. close $a_fd;
  23. close $b_fd;
  24. close $c_fd;
复制代码

论坛徽章:
0
4 [报告]
发表于 2013-03-03 20:51 |只看该作者
我一般的方法都是使用两个hash来解决此类问题,供大家参考一下:
定义两个hash:%m 和 %n,核心代码就是$m{$_}++ and $n{$_}++
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Data::Dumper;

  5. my @array1 = split /\n/, <<FILE1;
  6. 01 02 03 04 05 06
  7. 02 03 04 05 06 07
  8. 15 19 22 24 27 28 33 36
  9. 01 09 14 15 19 23
  10. FILE1

  11. my @array2 = split /\n/, <<FILE2;
  12. 01 02 03 04 05 06
  13. 02 03 04 05 06 07
  14. 05 06 07 08 09 10 11
  15. 03 04 05 06 07 08
  16. 05 07 09 11 13 14 15
  17. 08 10 14 15 17 22 23 25
  18. 11 12 16 18 19 41
  19. 22 24 29 34 37 39
  20. FILE2

  21. my (%m, %n);
  22. foreach ( @array1, @array2 ) {
  23.     $m{$_}++ and $n{$_}++;
  24. }

  25. print Dumper \%m;
  26. print Dumper \%n;
复制代码
结果如下:
  1. $VAR1 = {
  2.           '03 04 05 06 07 08' => 1,
  3.           '05 07 09 11 13 14 15' => 1,
  4.           '15 19 22 24 27 28 33 36' => 1,
  5.           '05 06 07 08 09 10 11' => 1,
  6.           '11 12 16 18 19 41' => 1,
  7.           '22 24 29 34 37 39' => 1,
  8.           '01 02 03 04 05 06 ' => 2,
  9.           '02 03 04 05 06 07' => 2,
  10.           '08 10 14 15 17 22 23 25' => 1,
  11.           '01 09 14 15 19 23' => 1
  12.         };
  13. $VAR1 = {
  14.           '01 02 03 04 05 06 ' => 1,
  15.           '02 03 04 05 06 07' => 1
  16.         };
复制代码
分析两个hash的结果值可以逐个推出实际需要的重复还是非重复数据:
1> 求两个数组中的重复项,可以直接是用%n取键值获得,或通过对%m的键值grep
  1. # intersection
  2. print "\nMethod1:\n";
  3. print "$_\n" for keys %n;
  4. print "\nMethod2:\n";
  5. print "$_\n" for grep { $m{$_} >= 2 } keys %m;
复制代码
结果如下:
Intersection1:
01 02 03 04 05 06
02 03 04 05 06 07

Intersection2:
01 02 03 04 05 06
02 03 04 05 06 07

2> 对两个数组去重,取%m的键值即可
  1. # union
  2. print "\nUnion:\n";
  3. print "$_\n" for keys %m;
复制代码
结果如下:
Union:
03 04 05 06 07 08
05 07 09 11 13 14 15
15 19 22 24 27 28 33 36
05 06 07 08 09 10 11
11 12 16 18 19 41
22 24 29 34 37 39
01 02 03 04 05 06
02 03 04 05 06 07
08 10 14 15 17 22 23 25
01 09 14 15 19 23
3> 求两个数组之间不同的项,是用grep对%m的键值操作
  1. # non-uniq
  2. print "\nNon-uniq:\n";
  3. print "$_\n" for grep { $m{$_} == 1 } keys %m;
复制代码
结果:
Non-uniq:
03 04 05 06 07 08
05 07 09 11 13 14 15
15 19 22 24 27 28 33 36
05 06 07 08 09 10 11
11 12 16 18 19 41
22 24 29 34 37 39
08 10 14 15 17 22 23 25
01 09 14 15 19 23

使用hash去重是效率很高的方法,但是缺点是无法保持数组中数据原来的顺序。

论坛徽章:
0
5 [报告]
发表于 2013-03-03 22:49 |只看该作者
本帖最后由 longbow0 于 2013-03-03 22:50 编辑

comm -12 1.txt 2.txt > 3.txt

不过只能用于sorted文件

论坛徽章:
0
6 [报告]
发表于 2013-03-04 00:21 |只看该作者
#!/usr/bin/perl
use strict;
use warnings;

my ($line,$l2);
my $i=1;
my $j=1;
open FILE,"<t.txt" or die "Can't open t: $!\n";
open F2,"<2.txt" or die "Can't open 2: $!\n";
open f3,">3.txt" or die "can not write 3: $!\n";
while ($line=<FILE>) {
        print "t.txt: ",$j++,"\n";
        chomp $line;
        while (defined($l2=<F2>)) {
                chomp $l2;
                    if ( $line eq $l2 ) { print f3 $line,"\n"}
                        print "2.txt: ",$i++,"\n";
        }
        seek F2,0,0;
        $i=1;
}
close FILE;
close F2;
close f3;

论坛徽章:
0
7 [报告]
发表于 2013-03-04 17:17 |只看该作者
diff 1.txt 2.txt | awk '/^</{print}' |sed 's/< //' > 3.txt
diff 1.txt 3.txt | awk '/^</{print}' | sed 's/< //'
sinian126 该用户已被删除
8 [报告]
发表于 2013-03-04 19:14 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
8
双子座
日期:2013-08-31 07:37:12金牛座
日期:2013-09-09 18:49:12处女座
日期:2013-09-23 11:43:14处女座
日期:2013-10-09 19:48:21狮子座
日期:2014-03-24 18:22:12丑牛
日期:2014-04-22 22:07:51申猴
日期:2014-06-12 21:54:13双鱼座
日期:2014-06-13 21:52:31
9 [报告]
发表于 2013-03-06 20:08 |只看该作者
try
  1. perl -ane 'print if(++$a{$_}>=2)'  1 2
复制代码
回复 1# apkood


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP