我正在尝试计算文本文件中特定单词出现的次数。文本文件作为perl程序的程序参数给出。
while($text = <>)
{
@words = split (/\W*\s+\W*/, $text);
@words = grep (/^[a-zA-Z\-]+$/, @words);
foreach $word (@words)
{
$wordCount{$word}++;
}
}
我对这些行没有清楚的认识 -
@words = split (/\W*\s+\W*/, $text);
@words = grep (/^[a-zA-Z\-]+$/, @words);
我知道split
会将字符串拆分为数组变量,但是如何?它是非单词吗?我不明白split函数中使用的正则表达式。
grep
做了什么以及它的正则表达式对我来说不清楚。
P.S。当我检查这个时,代码似乎有一个错误,因为如果我输入一个文本文件为 -
快速的棕色狐狸跳过了 懒狗dog.rose是棕色,紫罗兰色 跳了狐狸。
仅对单词fox
和dog
计算一次,这是不正确的。
这里有什么问题?
答案 0 :(得分:2)
我不确定拆分数组是最节省内存的方法,特别是对于非常大的文本。如果你有一个几兆字节的文本文件,你将构建一个非常大的数组,它会占用大量内存。
相反,我会做这样的事情:
while ($text = <>) {
while ($text =~ /([A-Za-z\-]+)/g) {
my $word = lc($1); # dont diffrentiate between 'Dog' and 'dog'
$count++; # total word count
$wordCount{$word}++; # individual word count
}
}
如果您碰巧找到任何希望包含在单词中的有效字符,那么添加新字符也很容易。即如果您认为this_file
可以接受,请将字符更改为[A-Za-z\-_]
。
关于你的问题:
正则表达式\W*\s+W*
表示:将非单词字符0与任意次数匹配,后跟一个任意数量的空格,后跟零到任意数量的非单词字符。一种奇怪的分割方式,但它基本上会在所有空格中分开,并删除过程中的所有非单词字符,以获得更正确的单个字数。 (例如,它不会将dog,
和dog
视为两个不同的词语。)
grep
本身将返回与正则表达式匹配的值列表。正则表达式将匹配@words
中仅包含(从头到尾)字母,大写或小写以及连字符的任何数组值。如果值内有任何其他字符,grep将排除它。
错误是"dog.rose"
和"fox."
无法正确拆分,因为没有空格。因此,它们不会被隐含地清除非单词字符,因此将使用grep.
答案 1 :(得分:1)
与这些问题一样,有一百万种不同的方式来定义“单词”是什么。将现有的一个在这里使用(允许使用内部破折号的字母序列),但使其适用于两个指出的失败案例:
my $text = 'the quick brown fox jumps over the lazy dog dog.rose is brown, violet jumps the fox.';
my %wordCount;
for my $word ( $text =~ /([a-zA-Z]+|-(?=[a-zA-Z\-])(?<=[a-zA-Z\-]-))+/g ) {
++$wordCount{$word};
}
for my $word ( sort { $wordCount{$a} <=> $wordCount{$b} || $a cmp $b } keys %wordCount ) {
print "$word: $wordCount{$word}\n"
}
答案 2 :(得分:0)
\W is matching word characters
\s is matching whitespace
正如您可能已经猜到的那样,它不起作用,因为dog.rose中的单词之间没有空格。
我会分开\ b(这意味着单词边界)。这应该比\ W * \ s + \ W *。
更简单,更正确while($text = <>)
{
@words = split (/\b/, $text);
foreach $word (@words)
{
$wordCount{$word}++;
}
}