2

我有一个包含 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”的行号,我的脚本也应该只匹配“hello”并给出它的行号。

4

6 回答 6

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";
    }
}

关键字.txt:

hello
foo
bar

搜索.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引号文字正则表达式运算符应用于每一行(这确保如果您有像“foo.bar”这样的关键字,它将把点视为文字字符,而不是正则表达式元字符)。

join '|',- 将结果列表连接成一个字符串,用竖线字符分隔。

my $regex = qr|\b($keyword_or)\b|;- 创建一个如下所示的正则表达式:

/\b(\Qhello\E|\Qfoo\E|\Qbar\E)\b/

此正则表达式将匹配您的任何关键字。\b是单词边界标记,确保只有整个单词匹配:food不再匹配foo。括号捕获匹配的特定关键字$1。这就是输出如何打印匹配的关键字。

我更新了解决方案以匹配给定行上的每个关键字,并且只匹配完整的单词。

于 2012-12-19T09:16:27.997 回答
6

这是更大的一部分吗?因为这是一个单衬里grep

grep -n hello filewithlotsalines.txt

grep -n "hello world" filewithlotsalines.txt

-n在匹配grep行之前首先显示行号。你可以做man grep更多的选择。

我在这里假设您使用的是 linux 或 *nix 系统。

于 2012-12-19T05:54:18.247 回答
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是通过对空列表的引用来初始化的。

'keywords' 文件的每一行都split在分隔选项卡上,如果在 中定义了相应的条目%lookupTable,则将行号push添加到相应的列表中。完成后,对%lookupTable键进行不区分大小写的排序并写入SampleLineNum.txt,以及找到条目的相应行号列表(如果有)。

输入的文件名没有完整性检查,因此请考虑添加这些。

希望这可以帮助!

于 2012-12-19T19:55:57.617 回答
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;
于 2012-12-19T06:43:28.647 回答
0

我认为有一些类似的问题。您可以查看:

File::Grep模块很有趣。

于 2012-12-19T09:18:52.513 回答
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
>
于 2012-12-19T09:19:41.850 回答