当grep在查找文件的长行中从模式文件中找到短模式时,我需要一个工具,它允许我提取在较长模式中可以找到的查找文件的短行。
换言之,鉴于莎士比亚的作品每行一句话,并说一本法语词典,我想找出哪个法语单词是在哪一行莎士比亚中找到的,允许检测一行莎士比亚可能包含多个法语单词以及一个法语单词可能出现在多行莎士比亚中的事实。
例如:
pattern_file={
"The sun is shining!"
"It is a beautiful day!"}
lookup_file={
"Rain"
"Sun"
"Cloud"
"Beautiful"
"Shining"}
我想要的是
function file pattern
给出在较长模式中找到的行和由昏迷分隔的较长模式本身,并检测到多个匹配项。
ideal_result_file={
"Sun","The sun is shining!"
"Beautiful","It is a beautiful day!",
"Shining", "The sun is shining!"}
目前,我使用grep逐行循环整个查找文件:
while read line
do
grep -is $line pattern_file | sed 's/^/'"$line"'\,/g' >> result_file.csv
done < lookup_file
这真是太慢了!我的查找文件包含50000多行,而模式文件包含500行。当使用grep在我的lookup_文件中找到一个更短的模式需要几秒钟时,使用循环方法的一次传递需要几天/几周的时间。
任何语言的解决方案都是值得赞赏的。
有点关系
Very slow loop using grep or fgrep on large datasets
Is Perl faster than bash?
该解决方案需要与GB大小的循环和模式文件兼容。
最佳答案
使用哈希表或集合(取决于您的语言)以所有小写形式存储字典。对于每一行,将行拆分为基于非字母字符的单词数组。基于这些单词构建一个小型哈希表,转换为小写,以消除重复项。遍历那个小哈希表中的每个单词,验证它是否存在于字典哈希表中。如果存在,打印单词和整行。
这是用Perl实现的。
#! /usr/bin/perl
my $dictFile=$ARGV[0];
my $srchFile=$ARGV[1];
(-f $dictFile and -f $srchFile) or die "Usage: $0 dictFile srchFile";
# Load dictionary into hash table
my %dict=();
open($df, "<$dictFile") or die "Cannot open $dictFile";
while (<$df>) {
chomp;
$dict{lc($_)}=1;
}
# Search file for your dictionary words
open($sf, "<$srchFile") or die "Cannot open $srchFile";
my $lineNo=0;
while ($line=<$sf>) {
$lineNo++;
chomp($line);
my %words=();
my @sentence=split(/[^a-zA-ZÀ-ÿ0-9]+/, $line);
foreach $word (@sentence) {
$words{lc($word)}=1;
}
while ( my ($key) = each(%words) ) {
if ($dict{$key}) {
print "$lineNo, $key, $line\n";
}
}
}
模式.txt
The sun is shining!
It is a beautiful day!
查找.txt
Rain
Sun
Cloud
Beautiful
Shining
$ ./deepfind lookup.txt pattern.txt
1, shining, The sun is shining!
1, sun, The sun is shining!
2, beautiful, It is a beautiful day!
编辑:根据你的评论,这里有一个在“句子”中定义“词”集合的替代方法。这将准备与字典中找到的任何序列长度匹配的所有可行序列。
#! /usr/bin/perl
my $dictFile=$ARGV[0];
my $srchFile=$ARGV[1];
(-f $dictFile and -f $srchFile) or die "Usage: $0 dictFile srchFile";
# Load sequence dictionary into hash table
my %dict=();
my %sizes=();
open($df, "<$dictFile") or die "Cannot open $dictFile";
while (<$df>) {
chomp;
$dict{lc($_)}=1;
$sizes{length($_)}=1;
}
# Search file for known sequences
open($sf, "<$srchFile") or die "Cannot open $srchFile";
my $lineNo=0;
while ($line=<$sf>) {
$lineNo++;
chomp($line);
# Populate a hash table with every unique sequence that could be matched
my %sequences=();
while ( my ($size) = each(%sizes) ) {
for (my $i=0; $i <= length($line)-$size; $i++) {
$sequences{substr($line,$i,$size)}=1;
}
}
# Compare each sequence with the dictionary of sequences.
while ( my ($sequence) = each(%sequences) ) {
if ($dict{$sequence}) {
print "$lineNo, $sequence, $line\n";
}
}
}