我有一个包含400000行的大文件,每行包含许多由标签分隔的关键字。
我还有一个文件,其中包含要匹配的关键字列表。说这个文件充当查找。
因此,对于查找表中的每个关键字,我需要在给定文件中搜索它的所有匹配项。并且应该打印出现的行号。
我试过这个
#!usr/bin/perl
use strict;
use warnings;
my $linenum = 0;
print "Enter the file path of lookup table:";
my $filepath1 = <>;
print "Enter the file path that contains keywords :";
my $filepath2 = <>;
open( FILE1, "< $filepath1" );
open FILE2, "< $filepath2" ;
open OUT, ">", "SampleLineNum.txt";
while( $line = <FILE1> )
{
while( <FILE2> )
{
$linenum = $., last if(/$line/);
}
print OUT "$linenum ";
}
close FILE1;
这将首次出现关键字。但我需要所有的出现,并且关键字应该完全匹配。
完全匹配面临的问题是,例如我有关键字“hello”和“hello world”
如果我需要匹配“hello”,它还会返回包含“hello world”的行号 我的脚本应该只匹配“你好”并给出它的行号。
答案 0 :(得分:7)
这是一个匹配所有关键字的每一个匹配项的解决方案:
#!usr/bin/perl
use strict;
use warnings;
#Lexical variable for filehandle is preferred, and always error check opens.
open my $keywords, '<', 'keywords.txt' or die "Can't open keywords: $!";
open my $search_file, '<', 'search.txt' or die "Can't open search file: $!";
my $keyword_or = join '|', map {chomp;qr/\Q$_\E/} <$keywords>;
my $regex = qr|\b($keyword_or)\b|;
while (<$search_file>)
{
while (/$regex/g)
{
print "$.: $1\n";
}
}
keywords.txt:
hello
foo
bar
search.txt:
plonk
food is good
this line doesn't match anything
bar bar bar
hello world
lalalala
hello everyone
输出:
4: bar
4: bar
4: bar
5: hello
7: hello
<强>解释强>
这会创建一个匹配关键字文件中所有关键字的正则表达式。
<$keywords>
- 当在列表上下文中使用它时,它返回文件所有行的列表。
map {chomp;qr/\Q$_\E/}
- 这会删除每一行的换行符,并将\Q...\E
quote-literal正则表达式运算符应用于每一行(这可确保如果您有一个像“foo.bar”这样的关键字,它会对待点作为文字字符,而不是正则表达式元字符。)
join '|',
- 将结果列表连接成一个字符串,用竖线字符分隔。
my $regex = qr|\b($keyword_or)\b|;
- 创建一个如下所示的正则表达式:
/\b(\Qhello\E|\Qfoo\E|\Qbar\E)\b/
此正则表达式将匹配您的任何关键字。 \b
是单词边界标记,确保只有整个单词匹配:food
不再匹配foo
。括号捕获在$1
中匹配的特定关键字。这是输出打印匹配关键字的方式。
我更新了解决方案,以匹配给定行上的每个关键字,并且只匹配完整的单词。
答案 1 :(得分:6)
这是更大的一部分吗?因为这是一个带有grep
grep -n hello filewithlotsalines.txt
grep -n "hello world" filewithlotsalines.txt
-n
获取grep
以在匹配的行之前显示行号。您可以man grep
获取更多选项。
我在这里假设您使用的是Linux或* nix系统。
答案 2 :(得分:1)
我对您的请求有不同的解释。您似乎可能希望维护一个行号列表,其中查找表中的某些条目位于“关键字”文件的行上。这是一个示例查找表:
hello world
hello
perl
hash
Test
script
以制表符分隔的“关键字”文件,其中可以在一行中找到多个关键字:
programming tests
hello everyone
hello hello world perl
scripting scalar
test perl script
hello world perl script hash
鉴于上述情况,请考虑以下解决方案:
use strict;
use warnings;
my %lookupTable;
print "Enter the file path of lookup table: \n";
chomp( my $lookupTableFile = <> );
print "Enter the file path that contains keywords: \n";
chomp( my $keywordsFile = <> );
open my $ltFH, '<', $lookupTableFile or die $!;
while (<$ltFH>) {
chomp;
undef @{ $lookupTable{$_} };
}
close $ltFH;
open my $kfFH, '<', $keywordsFile or die $!;
while (<$kfFH>) {
chomp;
for my $keyword ( split /\t+/ ) {
push @{ $lookupTable{$keyword} }, $. if defined $lookupTable{$keyword};
}
}
close $kfFH;
open my $slFH, '>', 'SampleLineNum.txt' or die $!;
print $slFH "$_: @{ $lookupTable{$_} }\n"
for sort { lc $a cmp lc $b } keys %lookupTable;
close $slFH;
print "Done!\n";
输出到SampleLineNum.txt
:
hash: 6
hello: 2 3
hello world: 3 6
perl: 3 5 6
script: 5 6
Test:
该脚本使用数组散列(HoA),其中键是查找表中的条目,关联值是对行号列表的引用,其中该条目在“关键字”文件的行上找到。哈希%lookupTable
初始化为对空列表的引用。
“关键字”文件的每一行在分隔标签上都是split
,如果在%lookupTable
中定义了相应的条目,则行号为push
。名单。完成后,%lookupTable
密钥不区分大小写,并写入SampleLineNum.txt
,以及找到条目的相应行号列表(如果有)。
对输入的文件名没有完整性检查,因此请考虑添加这些文件名。
希望这有帮助!
答案 3 :(得分:0)
要查找所有匹配项,您需要读取关键字,然后遍历关键字以查找每行的匹配项。这是我修改后使用数组在行中查找关键字的内容。另外,我添加了一个计数器来计算行号,然后 如果有匹配要打印以打印出行号。即使没有匹配,您的代码也会打印出每行的项目。
#!usr/bin/perl
use strict;
use warnings;
my $linenum = 0;
print "Enter the file path of lookup table:";
my $filepath1 = <>;
print "Enter the file path that contains keywords :";
my $filepath2 = <>;
open( FILE1, "< $filepath1" );
open FILE2, "< $filepath2" ;
# Read in all of the keywords
my @keywords = <FILE2>;
# Close the file2
close(FILE2);
# Remove the line returns from the keywords
chomp @keywords;
# Sort and reverse the items to compare the maximum length items
# first (hello there before hello)
@keywords = reverse sort @keywords;
foreach my $k ( @keywords)
{
print "$k\n";
}
open OUT, ">", "SampleLineNum.txt";
my $line;
# Counter for the lines in the file
my $count = 0;
while( $line = <FILE1> )
{
# Increment the counter for the number of lines
$count++;
# loop through the keywords to find matches
foreach my $k ( @keywords )
{
# If there is a match, print out the line number
# and use last to exit the loop and go to the
# next line
if ( $line =~ m/$k/ )
{
print "$count\n";
last;
}
}
}
close FILE1;
答案 4 :(得分:0)
答案 5 :(得分:0)
正如其他人已经给出了一些perl解决方案,我建议你可以在这里使用awk。
> cat temp
abc
bac
xyz
> cat temp2
abc jbfwerf kfnm
jfjkwebfkjwe bac xyz
ndwjkfn abc kenmfkwe bac xyz
> awk 'FNR==NR{a[$1];next}{for(i=1;i<=NF;i++)if($i in a)print $i,FNR}' temp temp2
abc 1
bac 2
xyz 2
abc 3
bac 3
xyz 3
>