【问题标题】:Extracting same lines from two files while disregarding lower/uppercase从两个文件中提取相同的行,同时忽略小写/大写
【发布时间】:2014-10-26 11:11:09
【问题描述】:

目的是从两个文件中提取相同的行,同时忽略小写/大写以及标点符号

我有两个文件

source.txt

Foo bar
blah blah black sheep
Hello World
Kick the, bucket

processed.txt

foo bar
blah sheep black
Hello world
kick the bucket ,

期望的输出(来自source.txt):

Foo bar

Hello World
Kick the, bucket

我一直这样做:

from string import punctuation
with open('source.txt', 'r') as f1, open('processed.txt', 'r') as f2:
  for i,j in zip(f1, f2):
    lower_depunct_f1 = " ".join("".join([ch.lower() for ch in f1 if f1 not in punctuation]).split())
    lower_depunct_f2 = " ".join("".join([ch.lower() for ch in f2 if f2 not in punctuation]).split())
    if lower_depunct_f1 == lower_depunct_f2:
      print f1
    else:
      print

有没有办法使用bash 工具来做到这一点? perl、shell、awk、sed?

【问题讨论】:

    标签: python bash perl unix awk


    【解决方案1】:

    使用awk 更容易做到这一点:

    awk 'FNR==NR {s=toupper($0); gsub(/[[:blank:][:punct:]]+/, "", s); a[s]++;next}
       {s=toupper($0); gsub(/[[:blank:][:punct:]]+/, "", s); print (s in a)?$0:""}' file2 file1
    Foo bar
    
    Hello World
    Kick the, bucket
    

    【讨论】:

    • 它是否将整个文件加载到内存中?在 150 万行上进行测试时没有打印任何内容 =(
    • 它仅将第一个文件中的行加载到内存中,然后将其与第二个文件进行比较。此外,您在问题中也没有提到大量数据。
    • 哦,它在几秒钟后工作,不用担心,只要它工作得相当快,就可以了
    • 是的,它确实有效,但过去几天我的互联网连接不佳,我会尽快重新研究这个问题......
    【解决方案2】:

    Perl 解决方案与 Python 解决方案非常相似:

    open my $S1, '<', 'source.txt'    or die $!;
    open my $S2, '<', 'processed.txt' or die $!;
    while (defined(my $s1 = <$S1>) and defined (my $s2 = <$S2>)) {
        s/[[:punct:]]//g for $s1, $s2;
        $_ = lc for $s1, $s2;
        print $s1 eq $s2 ? $s1 : "\n";
    }
    

    请注意,结果与您的不同,因为kick the bucket 后面的空格没有被删除。

    【讨论】:

      【解决方案3】:

      Bash 解决方案,与 Perl 解决方案非常相似,但结果相同(因为 kick the bucket 后面的空格没有被删除):

      #!/bin/bash
      
      shopt -s nocasematch
      
      exec 3<> source.txt              # Open source.txt and assign fd 3 to it.
      exec 4<> processed.txt
      while read <&3 varline && read <&4 varpro
      do
          varline_noPunct=`echo $varline | tr -d '[:punct:]'`
          varpro_noPunct=`echo $varpro | tr -d '[:punct:]'`
          [[ $varline_noPunct == $varpro_noPunct ]] && echo "$varline" || echo 
      done
      exec 3>&-       # Close fd 3.
      exec 4>&- 
      

      【讨论】:

        【解决方案4】:

        检查此解决方案是否对您有帮助:

        use strict;
        use warnings;
        
        my $f1 = $ARGV[0];
        open FILE1, "<", $f1 or die $!;
        my $f2 = $ARGV[1];
        open FILE2, "<", $f2 or die $!;
        
        
        open OUTFILE, ">", "cmp.txt" or die $!;
        
        my %seen;
        while (<FILE1>) {
              $_ =~ s/[[:punct:]]//isg;     
            $seen{lc($_)} = 1;
        }
        
        while (<FILE2>) {
            my $next_line = <FILE2>;
            $_ =~ s/[[:punct:]]//isg;
            if ($seen{lc($_)}) {    
                print OUTFILE $_;
            }
        }
        close OUTFILE;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-23
          • 1970-01-01
          • 2023-03-15
          • 1970-01-01
          • 2011-10-06
          • 1970-01-01
          相关资源
          最近更新 更多