【问题标题】:Perl - How to handle huge files for searching similar wordsPerl - 如何处理用于搜索相似词的大文件
【发布时间】:2014-06-20 08:50:53
【问题描述】:

我正在处理大文件。我想知道,在您看来,当您想知道 $file1 中的单词“x”是否出现在 file2 的句子“y”中时,处理大文件的最佳方法是什么。 我的文件有超过 20000 行..

例子:

这是第一个文件的内容:

eat
take
breath
you
alpha

这是第二个文件的内容:

eat,hungry
love,lovers
me,mine
take,taken,give
you,u,yo
fun,funny

这是我可能期望的第三个文件的内容

eat : eat,hungry
take : take,taken,give
you : you,u,yo

所以如你所见,我想在第一个文件的单词的第二个文件中找到匹配的表达式。

我的解决方案 - 但循环永远不会结束 -

解决方案1:

$file1= "words.txt";
$file2 = "expressions.txt";
$out = "out.txt";

open (W, "<", $file1);
open (E, "<", $file2);
open (OUT, ">", $out);

while(defined($l = <W>)){
    @a = split (/\n/, $l);
    push @w, @a;
}

while(defined($l2 = <E>)){
    for ($i = 0; $i < @w; $i++){
        if (grep /\Q\b$w[$i]\b\E/, $l2){ #or just /\b$w[$i]\b/
            print OUT "$w[$i] : $l2\n";
        }
    }
}

解决方案2:

$file1= "words.txt";
$file2 = "expressions.txt";
$out = "out.txt";

open (W, "<", $file1);
open (E, "<", $file2);
open (OUT, ">", $out);

while(defined($l = <W>)){
    @a = split (/\n/, $l);
    push @w, @a;

while(defined($l2 = <E>)){
    @b = split (/\n/, $l2);
    push @e, @b;
}

for ($k = 0; $k < @e; $k++){
    for ($i = 0; $i < @w; $i++){
        if (grep /\b$w[$i]\b/, $e[$k]){
            print OUT "$w[$i] : $w[$l]\n";
        }
    }
}

【问题讨论】:

  • 旁注,$l2 =~ /\Q\b$w[$i]\b\E/grep /\Q\b$w[$i]\b\E/, $l2 更好,如果你想匹配单词边界而不是字面 \b 然后 /\b\Q$w[$i]\E\b/
  • 好的,我编辑了。但是,为什么第一个表达式更好?
  • $l2 =~ .. 更好,因为它可以更好地传达意图,即匹配正则表达式与单个字符串。

标签: perl grep filehandle


【解决方案1】:

如何先处理表达式文件,使字典将每个单词映射到一个句子,然后查找words.txt中的单词是否在字典中?我想这可能会更快。源码如下:

#! /opt/VRTSperl/bin/perl

    $words = "words.txt";
    $expressions = "expressions.txt";
    $out = "out.txt";

    open (E, "<", $expressions);
    open (W, "<", $words);
    open (OUT, ">", $out);

    my %dic;

    while (my $sentence = <E>) {
        chomp($sentence);
        my @words = split(/,/, $sentence);
        foreach my $word (@words) {
            $dic{$word} .= "$sentence";
        }   
    }

    while (my $word = <W>) {
        chomp($word);
        if ($dic{$word}) {
            print OUT "$word : $dic{$word}\n"
        }   
    }

【讨论】:

  • 真的吗?在我这边,输出文件是 eat : eat,hungry take : take,taken,give you : you,u,yo
【解决方案2】:
#!/usr/local/bin/perl
use strict;
use warnings;
open (my $fh, "<", "f1.txt") or die $!;
open (my $fh2, "<", "f2.txt") or die $!;
my @keys;
while(chomp(my $line = <$fh>)){
        push @keys, $line;
}
while(chomp(my $line2 = <$fh2>)){
        foreach (@keys){
                if ($line2 =~ $_){
                        print "$_ : $line2\n";
                }
        }
}

输出

eat : eat,hungry
take : take,taken,give
you : you,u,yo

【讨论】:

  • 如果单词在中间,它会起作用吗?例如。单词是“a”,表达式是“c,a,b”。
  • 10 分钟后仍在运行。但是我已经注意到一些错误 -> continue : continuellement, constamment
  • 对不起,我不明白,请通过编辑重新表述您的问题,我很乐意提供帮助。
  • 对不起!例如。在文件 1 中有“继续”一词,在文件 2 中有“继续,约束”......所以看起来“继续”与“继续”是一样的,所以我认为它不承认权利单词。另一个问题是:如果“继续”一词位于文件 2 的表达式中间(例如,“继续,继续,继续”,我认为您的代码不起作用。我是否更好地解释了这个问题?
【解决方案3】:

您正在尝试匹配文字 \b 而不是单词边界,所以

/\Q\b$w[$i]\b\E/

应该是

/\b\Q$w[$i]\E\b/

【讨论】:

    猜你喜欢
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 2013-04-26
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    相关资源
    最近更新 更多