Подсчет отдельных слов в текстовом файле - PullRequest
3 голосов
/ 30 мая 2011

Я пытаюсь подсчитать, сколько раз конкретное слово встречалось в текстовом файле.Текстовый файл передается в качестве аргумента программы 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, и снова его регулярное выражение мне неясно.

PS Когда я проверяю это, код кажетсячтобы иметь ошибку, в том случае, если я ввожу текстовый файл с текстом -

быстрая коричневая лиса перепрыгивает через ленивую собаку. роза коричневая, фиолетовая прыгает по лисе.

Считает слова fox и dog только один раз, что неверно.

Что здесь не так?

Ответы [ 3 ]

2 голосов
/ 30 мая 2011

Я не уверен, что разбиение на массив - это самый эффективный способ памяти, особенно для очень больших текстов.Если у вас есть текстовый файл размером в несколько мегабайт, вы создадите очень большой массив, который будет использовать много памяти.

Вместо этого я бы сделал что-то вроде этого:

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* означает: соответствует нулевому символу без словалюбое количество раз, после которого следует один для любого количества пробелов, после которого следует ноль для любого количества несловесных символов.Довольно странный способ разделения, но он в основном разделит все пробелы и удалит все несловарные символы в процессе для более точного индивидуального подсчета слов.(Например, он не будет трактовать dog, и dog как два разных слова).

Сам по себе grep вернет список значений, соответствующих регулярному выражению.Регулярное выражение будет соответствовать любому значению массива в @words, которое состоит только из (от начала до конца) букв, верхнего или нижнего регистра и дефиса.Если внутри значения есть какой-либо другой символ, grep исключит его.

Ошибка в том, что "dog.rose" и "fox." не будут разделены правильно, потому что нет пробелов.Поэтому они не будут неявно очищены от несловесных символов и, следовательно, будут удалены с помощью grep.

1 голос
/ 30 мая 2011

Как всегда с этими вопросами, есть миллион различных способов определить, что такое «слово». Взять существующий, который используется здесь (последовательность букв с внутренними штрихами), но заставить его работать с двумя отмеченными ошибками:

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" 
}
0 голосов
/ 30 мая 2011
\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}++;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...