【问题标题】:Match substring from a list to multiple columns in another file将列表中的子字符串匹配到另一个文件中的多个列
【发布时间】:2017-09-10 08:20:27
【问题描述】:

我对 linux 和 perl 编程相当陌生。我已经用尽了所有搜索选项,没有答案。 我有一个主文件“master.txt”,其中包含所有已知的交互,其中 2 列已知同一行上的项目进行交互。我有一个项目列表“list.txt”,如果它包含在第 1 列和第 2 列中,我希望将其作为从主文件返回结果的搜索条件。所有文件都是制表符分隔的。例如: 如果这是主文件:“master.txt”

AppleP001   BallP002
AppleP002   CatP001 
BallP001    DogP001
BallP002    AppleP001
CatP001 AppleP002
DogP001 BallP001
DogP002 ZebraP001
ElephantP001    CardinalP001
FishP001    AntelopeP001

还有这个搜索文件:“list.txt”

Apple
Ball
Cat
Dog

生成的文件应该只在两列中包含 Apple*、Ball*、Cat* 和 Dog*,但删除重复项:

我尝试使用 grep:

grep -f list.txt master.txt > Sub_list.txt

但我明白了:

AppleP001       BallP002
AppleP002       CatP001
BallP001        DogP001
BallP002        AppleP001
CatP001 AppleP002
DogP001 BallP001
DogP002 ZebraP001

如何删除重复项(如果两个项目都在同一行中,则将其视为重复项,无论它们在哪一列中)并从输出文件中删除不相关的数据并获取它?

AppleP001   BallP002
AppleP002   CatP001 
BallP001    DogP001 

非常感谢任何帮助!谢谢。

【问题讨论】:

  • 欢迎来到 SO。请注意,此处的问题应与您的代码 的详细信息(以及失败的原因)有关。查看Help pages,它们简短且内容丰富。

标签: perl unix text-processing


【解决方案1】:

如果文件很大但没有提到这个问题,那就有点重了

use warnings;
use strict;
use feature 'say';
use Path::Tiny;
use List::Util qw(uniq any all);

my ($file, $flist) = ('master.txt', 'list.txt'); 

my @search = path($flist)->lines({ chomp => 1 });

# Sort words within each line so then filter out duplicate lines
my @filtered = uniq map { join ' ', sort split } path($file)->lines;

# Each word on the line needs to match a word in @search list
my @result = grep { all { found($_, \@search) } split } @filtered;

say for @result;

sub found { return any { $_[0] =~ /^$_/ } @{$_[1]} }

输出与我对问题描述的理解一致

苹果P001 球P002 苹果P002 CatP001 球P001 狗P001

如果由于某种原因您不能让Path::Tiny 提供path,请打开文件并检查它,而不是path(...)->lines 读取文件句柄(所以在列表上下文中)并执行chomp @search;


最后一部分,写了一点

# Each word on the line needs to match a word in @search list
my @result = grep { 
    my ($w1, $w2) = split; 
    any { $w1 =~ /^$_/ } @search  and  any { $w2 =~ /^$_/ } @search;
} @filtered;

【讨论】:

  • 谢谢zdim! cmets 非常有帮助,帮助我学习了您的代码。
【解决方案2】:

这是 awk 中的一个:

$ awk '
NR==FNR { a[$1]; next }    # read list and hash to a
{                          # process master
    b=""                   # reset buffer
    for(i in a)            # iterate thru a
        if(index($0,i)) {  # if list item is found in current master record
            b=$0           # set the record to buffer
            delete a[i]    # remove list entry from a
        }
        if(b) print b      # print b
}' list master             # mind the order
AppleP001   BallP002
AppleP002   CatP001 
BallP001    DogP001

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    相关资源
    最近更新 更多