【发布时间】:2011-10-18 23:21:22
【问题描述】:
编辑:我原来的标题已经改变了。我怀疑现在的标题并没有揭示我最初的目的:让 Perl 自动使用一个文件的内容作为搜索关键字的来源来搜索另一个文件,然后将匹配结果输出到第三个文件。。 p>
这意味着如果没有这种自动化,我将不得不手动输入FILE1 中列出的那些查询词,并通过简单地编写类似while(<FILE2>){if (/query terms/){print FILE3 $_}} 的内容一次从FILE2 获取匹配项。
更具体地说,FILE1 应该如下所示:
azure
Byzantine
cystitis
dyspeptic
eyrie
fuzz
FILE2 可能(或可能不会)看起来像这样:
azalea n. flowering shrub of the rhododendron family
azure adj. bright blue, as of the sky
byte n. fixed number of binary digits, often representing a single character
Byzantine adj. of Byzantium or the E Roman Empire
cystitis n. inflammation of the bladder
Czech adj. of the Czech Republic or Bohemia
dyslexic adj. suffering from dyslexia
dyspeptic adj. suffering from dyspepsia
eyelet n. small hole in cloth, in a sail, etc for a rope, etc to go through;
eyrie n. eagle's nest
fuzz n. mass of soft light particle
fuzzy adj. like fuzz
如果FILE2 是上面的样子,FILE3 应该看起来像这样:
azure adj. bright blue, as of the sky
Byzantine adj. of Byzantium or the E Roman Empire
cystitis n. inflammation of the bladder
dyspeptic adj. suffering from dyspepsia
eyrie n. eagle's nest
fuzz n. mass of soft light particle
我花了几个小时的反复试验才最终找出一个看似可行的解决方案,但我的代码可能有问题,更不用说效率低下了。如果我错了,我希望你们能把我送到正确的轨道上,请给我一些指导并与我分享一些解决问题的不同方法(嗯,必须有)。正如 daotoad 所建议的,我试图注释掉每一行代码的作用。如果我误解了什么,请纠正我。
#!perl #for Windows, simply perl suffices. I'm reading *Learning Perl*.
use warnings; #very annoying I've always been receiving floods of error messages
use strict; #I often have to look here and there because of my carelessness
open my $dic,'<', 'c:/FILE2.txt' or die "Cannot open dic.txt ;$!"; # 3-argument version of open statement helps avoid possible confusion; Dunno why when I replace dic.txt with $dic in the death note, I'll receive "needs explicit package name" warning. Any ideas?
open my $filter,'<','c:/FILE1.txt' or die "Cannot open new_word.txt :$!";
my @filter=<$filter>; #store the entire contents of FILE1 into @filter.
close $filter; #FILE1 is useless so close the connection between FILE1 and perl
open my $learn,'>','c:/FILE3.txt'; #This file is where I output matching lines.
my $candidate=""; #initialize the candidate to empty string. It will be used to store matching lines. Learnt this from Jeff.
while(<$dic>){ #let perl read the contents of FILE2 line by line.
for (my $n=0; $n<=$#filter; $n++){ #let perl go through each line of FILE1 too
my $entry = $filter[$n];
chomp($entry); #Figured out this line must be added after many fruitless attempts
if (/^$entry\s/){ #let perl compare each line of FILE2 with any line of FILE1.
$candidate.= $_ ; } #every time a match is found, store the line into $candidate
}
}
print $learn $candidate; #output the results to FILE3
更新 1:
非常感谢您的指导!我真的很感激:)
我相信我现在正朝着与我最初打算的方向有些不同的方向前进。哈希的概念超出了我当时的 Perl 知识储备。完成了学习 Perl 的哈希部分后,我现在在想:虽然使用哈希可以有效地解决我上面发布的示例问题,但如果定义文件 (@987654332) 中的词条(不是整个条目),情况可能会变得复杂@) 有重复。
但另一方面,我看到哈希在 Perl 编程中非常重要。所以今天早上我尝试实现@mobrule 的想法:将FILE1 的内容加载到哈希中,然后检查FILE2 中每一行的第一个单词是否在您的哈希表中。但后来我决定我应该加载@ 987654335@ 转换为哈希而不是 FILE1,因为 FILE2 包含字典条目,将 HEADWORDS 视为 KEYS 并将 DEFINITIONS 视为 VALUES 是有意义的。现在我想出了以下代码。似乎离成功很近了。
#!perl
open my $learn,'>','c:/file3.txt' or die "Cannot open Study Note;$!";
open my $dic,"<",'c:/file2.txt' or die "Cannot open Dictionary: $!";
my %hash = map {split/\t+/} <$dic>; # #I did some googling on how to load a file into a hash and found this works. But actually I don't quite understand why. I figured the pattern out by myself. /\t+/ seems to be working because the headwords and the main entries in FILE2 are separated by tabs.
open my $filter,'<','c:/file1.txt' or die "Cannot open Glossary: $!";
while($line=<$filter>){
chomp ($line);
if (exists $hash{$line}){
print "$learn $hash{$line}"; # this line is buggy. first it won't output to FILE3. second, it only prints the values of the hash but I want to include the keys.
}
}
代码在屏幕上输出以下结果:
GLOB(0x285ef8) adj. bright blue, as of the sky
GLOB(0x285ef8) adj. of Byzantium or the E Roman Empire
GLOB(0x285ef8) n. inflammation of the bladder
GLOB(0x285ef8) adj. suffering from dyspepsia
GLOB(0x285ef8) n. eagle's nest
GLOB(0x285ef8) n. mass of soft light particle
更新 2:
解决了一个问题。我现在可以通过对最后一行进行小修改来打印键和值。
print "$learn $line: $hash{$line}";
更新 3:
哈哈:我做到了!我做到了:)我再次修改了代码,现在它输出了东西到FILE3!
#!perl
open my $learn,'>','c:/file3.txt' or die $!;
open my $dic,"<",'c:/file2.txt' or die $!;
my %hash = map {split/\t+/} <$dic>; #the /\t+/ pattern works because the entries in my FILE2 are separated into the headwords and the definition by two tab spaces.
open my $filter,'<','c:/file1.txt' or die $!;
while($line=<$filter>){
chomp ($line);
if (exists $hash{$line}){
print $learn "$line: $hash{$line}";
}
}
更新 4:
我在想,如果我的FILE2 的内容完全不同,比如包含FILE1 中的查询词的句子,那么我们使用哈希方法会很困难,即使不是不可能,对吧?
更新 5:
仔细阅读了关于拆分运算符的 perlfunc 页面,现在我知道如何改进我的代码了 :)
#!perl
open my $learn,'>','c:/file3.txt' or die $!;
open my $dic,"<",'c:/file2.txt' or die $!;
my %hash = map {split/\s+/,$_,2} <$dic>; # sets the limit of separate fields to 2
open my $filter,'<','c:/file1.txt' or die $!;
while($line=<$filter>){
chomp ($line);
if (exists $hash{$line}){
print $learn "$line: $hash{$line}";
}
}
【问题讨论】:
-
没有用这个评论回答你的问题,只是想指出大多数 perl 黑客识别句柄(包括文件句柄),所有大写的裸词。例如,您将拥有 DIC、FILTER 和 LEARN。此外,读写字符可以包含在文件名中,例如 ">c:/file3.txt"。
-
在 Perl 中,文件句柄只是一个文件句柄,而不是文件名,因此在错误消息中打印 $dic 将没有用。它给出错误的原因是
my $dic声明了一个变量并返回它(因此在您的代码中打开将能够设置它)但语句中其他提及的 $dic 仍将引用 $dic 之前的任何内容宣言;直到以下语句之前,对 $dic 的额外提及才与刚刚声明的词法相关联。这允许my $dic = $dic;之类的东西(声明一个新词法,设置为以前的词法或全局的值。) -
@fatcat1111,perl 黑客?啊,那么这是深奥的东西。感谢分享:)
-
@ysth,感谢您的澄清!我还记得在《Learning Perl》这本书中,有句话说 filehand 不一定是文件名,而是 Perl 与外部世界之间联系的名称。我想我误会了什么。
-
@fatcat1111 全大写的bareword 文件句柄和双参数的open 都源于旧的做事方式,如果你想编写好的代码,它们都是坏习惯。迈克的开局代表了一种好的方法。