Regex 计算文本文件中的单个单词

Regex 计算文本文件中的单个单词,regex,perl,Regex,Perl,我试图计算一个特定单词在文本文件中出现的次数。文本文件作为程序参数提供给perl程序 while($text = <>) { @words = split (/\W*\s+\W*/, $text); @words = grep (/^[a-zA-Z\-]+$/, @words); foreach $word (@words) { $wordCount{$word}++; } } 我知道split将把字符串分割成数组变量,但是如

我试图计算一个特定单词在文本文件中出现的次数。文本文件作为程序参数提供给perl程序

while($text = <>)
{
    @words = split (/\W*\s+\W*/, $text);
    @words = grep (/^[a-zA-Z\-]+$/, @words);
    foreach $word (@words)
    {
        $wordCount{$word}++;
    }
}
我知道
split
将把字符串分割成数组变量,但是如何分割呢?它是非文字的吗?我不明白拆分函数中使用的正则表达式

grep
是做什么的,我也不清楚它的正则表达式

另外,当我检查这个时,代码似乎有一个bug,如果我输入一个文本文件,其中的文本为-

那只敏捷的棕色狐狸跳过了树 懒惰的狗。玫瑰是棕色的,紫色的 狐狸跳了起来

它只计算单词
fox
dog
一次,这是不正确的

这里怎么了

\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}++;
    }
}
while($text=)
{
@words=拆分(/\b/,$text);
foreach$word(@words)
{
$wordCount{$word}++;
}
}

与这些问题一样,有一百万种不同的方法来定义“单词”是什么。在这里使用现有的一个(允许带有内部破折号的字母序列),但使其适用于两个已知的失败情况:

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" 
}
my$text='敏捷的棕色狐狸跳过懒惰的狗。玫瑰是棕色的,紫罗兰跳过狐狸。';
我的%字数;

对于我的$word($text=~/([a-zA-Z]+|-(?=[a-zA-Z\-])(?我不确定拆分成数组是否是最节省内存的方法,特别是对于非常大的文本。如果你有一个几兆字节的文本文件,你将构建一个非常大的数组,这将占用大量内存

相反,我会这样做:

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
    }
}
while($text=){
而($text=~/([A-Za-z\-]+)/g){
我的$word=lc($1)#不要区分“狗”和“狗”
$count++#总字数
$wordCount{$word}++#单个单词计数
}
}
然后,如果您碰巧在一个单词中找到任何您希望包含为有效字符的字符,那么添加新字符也很容易。例如,如果您认为
此\u文件
可以接受,请将字符更改为
[a-Za-z\-\u]

关于你的问题:

regex
\W*\s+W*
的意思是:将非单词字符零与任意次数匹配,后跟一与任意数量的空格,后跟零与任意数量的非单词字符。这是一种非常奇怪的分割方法,但它基本上会围绕所有空格进行分割,并在此过程中删除所有非单词字符,以获得更正确的indi单个单词计数。(例如,它不会将
dog、
dog
视为两个不同的单词)

grep
本身将返回与正则表达式匹配的值列表。正则表达式将匹配
@words
中仅由字母、大写或小写以及连字符组成的任何数组值。如果值中有任何其他字符,grep将将其排除


错误是
“dog.rose”
“fox”
不会被正确拆分,因为没有空格。因此它们不会被隐式清除非单词字符,因此将被
grep删除。

@cellcortex:我相信\W字符类实际上与任何非单词字符匹配。如果有错,请纠正我。\W是非单词字符,\W是单词字符如果单词可能包含-,则rs\b将不起作用,从代码的其余部分可以明显看出这一点。边界的问题是,它在
上也会像“it's”一样分裂,而“it's”将变成“it”和“s”。最初使用的正则表达式非常聪明。它适用于空格和其他情况。@ysth:正确。带连字符'-'的单词,连字符也算作单词。但除此之外,/\b/解决了我前面的问题。不过,您需要区分“Dog”和“Dog”。
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
    }
}