[英]Use Perl to count occurrences of all words in a file or in all files in a directory
因此,我試圖編寫一個Perl腳本,該腳本將包含3個參數。
它似乎在遞歸地搜索目錄並查找文件中所有單詞的出現並將其打印到控制台中。
如何將它們打印到輸出文件中,如何將第二個參數(即數字,即5)打印到控制台,同時將出現次數最多的單詞數打印到控制台?文件?
以下是我到目前為止的內容:
#!/usr/bin/perl -w
use strict;
search(shift);
my $input = $ARGV[0];
my $output = $ARGV[1];
my %count;
my $file = shift or die "ERROR: $0 FILE\n";
open my $filename, '<', $file or die "ERROR: Could not open file!";
if ( -f $filename ) {
print("This is a file!\n");
while ( my $line = <$filename> ) {
chomp $line;
foreach my $str ( $line =~ /\w+/g ) {
$count{$str}++;
}
}
foreach my $str ( sort keys %count ) {
printf "%-20s %s\n", $str, $count{$str};
}
}
close($filename);
if ( -d $input ) {
sub search {
my $path = shift;
my @dirs = glob("$path/*");
foreach my $filename (@dirs) {
if ( -f $filename ) {
open( FILE, $filename ) or die "ERROR: Can't open file";
while ( my $line = <FILE> ) {
chomp $line;
foreach my $str ( $line =~ /\w+/g ) {
$count{$str}++;
}
}
foreach my $str ( sort keys %count ) {
printf "%-20s %s\n", $str, $count{$str};
}
}
# Recursive search
elsif ( -d $filename ) {
search($filename);
}
}
}
}
這將總計出現在命令行上給出的目錄或文件中的單詞:
#!/usr/bin/env perl
# wordcounter.pl
use strict;
use warnings;
use IO::All -utf8;
binmode STDOUT, 'encoding(utf8)'; # you may not need this
my @allwords;
my %count;
die "Usage: wordcounter.pl <directory|filename> number \n" unless ~~@ARGV == 2 ;
if (-d $ARGV[0] ) {
push @allwords, $_->slurp for io($ARGV[0])->all_files;
}
elsif (-f $ARGV[0]) {
@allwords = io($ARGV[0])->slurp ;
}
while (my $line = shift @allwords) {
foreach ( split /\s+/, $line) {
$count{$_}++
}
}
my $count_to_show;
for my $word (sort { $count{$b} <=> $count{$a} } keys %count) {
printf "%-30s %s\n", $word, $count{$word};
last if ++$count_to_show == $ARGV[1];
}
通過修改sort
和/或io
調用,您可以針對文件或目錄中的所有文件,按出現次數sort { }
(按字母順序)進行排序。 這些選項很容易添加為參數。 還可以過濾或改變如何字用於包括在被限定%count
,通過改變散列foreach ( split /\\s+/, $line)
的說法,包括一個匹配/過濾器如foreach ( grep { length le 5 } split /\\s+/, $line)
,以便僅計算五個或更少字母的單詞。
示例在當前目錄中運行:
./wordcounter ./ 10
the 116
SV 87
i 66
my_perl 58
of 54
use 54
int 49
PerlInterpreter 47
sv 47
Inline 47
return 46
注意事項
> filename.txt
即可;-) IO::All
不是標准的CORE IO包,我只是在這里做廣告和促銷;-)(您可以將其交換掉) sort_by
選項( -n --numeric
-a --alphabetic
, -a --alphabetic
等 ),則Sort::Maker
可能是使該選項易於管理的一種方法。 EDIT忽略了按OP請求添加選項。
我建議重組您的程序/腳本。 您發布的內容很難遵循。 一些評論可能有助於了解正在發生的事情。 我將嘗試通過一些代碼片段來安排事情,以希望有助於解釋項目。 我將介紹您在問題中概述的三個項目。
由於第一個參數可以是文件或目錄,因此我將使用-f和-d來檢查以確定什么是輸入。 我將使用列表/數組包含要處理的文件列表。 如果只是一個文件,我將其推送到處理列表中。 否則,我將調用一個例程以返回要處理的文件列表(類似於您的搜索子例程)。 就像是:
# List file files to process
my @fileList = ();
# if input is only a file
if ( -f $ARGV[0] )
{
push @fileList,$ARGV[0];
}
# If it is a directory
elsif ( -d $ARGV[0] )
{
@fileList = search($ARGV[0]);
}
因此,在搜索子例程中,您需要一個列表/數組,將要放入文件的項目壓入該列表/數組,然后從子例程返回該數組(在處理了來自glob調用的文件列表之后)。 當您擁有目錄時,可以使用路徑(就像您當前正在執行的那樣)調用搜索,將路徑推入當前數組中,例如
# If it is a file, save it to the list to be returned
if ( -f $filename )
{
push @returnValue,$filename;
}
# else if a directory, get the files from the directory and
# add them to the list to be returned
elsif ( -d $filename )
{
push @returnValue, search($filename);
}
獲得文件列表后,循環遍歷每個文件(打開,閱讀結尾的行,處理單詞的行)。 您用於處理每一行的foreach循環可以正常工作。 但是,如果您的單詞帶有句點,逗號或其他標點符號,則可能需要先刪除這些項目,然后再將其計算為哈希值。
在下一部分中,您詢問了如何確定計數最高的單詞。 在這種情況下,您要創建另一個具有計數鍵(每個單詞)的哈希,並且該哈希的值是與該計數數量關聯的單詞的列表/數組。 就像是:
# Hash with key being a number and value a list of words for that number
my %totals= ();
# Temporary variable to store occurrences (counts) of the word
my $wordTotal;
# $w is the words in the counts hash
foreach my $w ( keys %counts )
{
# Get the counts for the word
$wordTotal = $counts{$w};
# value of the hash is an array, so de-reference the array ( the @{ },
# and push the value of the counts array onto the array
push @{ $totals{$wordTotal} },$w; # the key to total is the value of the count hash
# for which the words ($w) are the keys
}
要獲得具有最高計數的單詞,您需要從總數中獲取鍵,並反轉排序列表(數字排序)以獲取N個最高的數字。 由於我們有一個值數組,因此我們將必須對每個輸出進行計數以獲得N個最高計數值。
# Number of items outputted
my $current = 0;
# sort the total (keys) and reverse the list so the highest values are first
# and go through the list
foreach my $t ( reverse sort { $a <=> $b} keys %totals) # Use the numeric
# comparison in
# the sort
{
# Since each value of total hash is an array of words,
# loop through that array for the values and print out the number
foreach my $w ( sort @{$total{$t}}
{
# Print the number for the count of words
print "$t\n";
# Increment the number output
$current++;
# if this is the number to be printed, we are done
last if ( $current == $ARGV[1] );
}
# if this is the number to be printed, we are done
last if ( $current == $ARGV[1] );
}
打印到文件的第三部分,尚不清楚您的問題中的“它們”是什么(單詞,計數或兩者;限於前幾個或所有單詞)。 我將把精力放在打開文件,將信息打印到文件上並關閉文件上。
我已經知道了。 以下是我的解決方案。 我不確定這是否是最好的方法,但確實有效。
# Check if there are three arguments in the commandline
if (@ARGV < 3) {
die "ERROR: There must be three arguments!\n";
exit;
}
# Open the file
my $file = shift or die "ERROR: $0 FILE\n";
open my $fh,'<', $file or die "ERROR: Could not open file!";
# Check if it is a file
if (-f $fh) {
print("This is a file!\n");
# Go through each line
while (my $line = <$fh>) {
chomp $line;
# Count the occurrences of each word
foreach my $str ($line =~ /\b[[:alpha:]]+\b/) {
$count{$str}++;
}
}
}
# Check if the INPUT is a directory
if (-d $input) {
# Call subroutine to search directory recursively
search_dir($input);
}
# Close the file
close($fh);
$high_count = 0;
# Open the file
open my $fileh,'>', $output or die "ERROR: Could not open file!\n";
# Sort the most occurring words in the file and print them
foreach my $str (sort {$count{$b} <=> $count{a}} keys %count) {
$high_count++;
if ($high_count <= $num) {
printf "%-31s %s\n", $str, $count{$str};
}
printf $fileh "%-31s %s\n", $str, $count{$str};
}
exit;
# Subroutine to search through each directory recursively
sub search_dir {
my $path = shift;
my @dirs = glob("$path/*");
# Loop through filenames
foreach my $filename (@dirs) {
# Check if it is a file
if (-f $filename) {
# Open the file
open(FILE, $filename) or die "ERROR: Can't open file";
# Go through each line
while (my $line = <FILE>) {
chomp $line;
# Count the occurrences of each word
foreach my $str ($line =~ /\b[[:alpha:]]+\b/) {
$count{$str}++;
}
}
# Close the file
close(FILE);
}
elsif (-d $filename) {
search_dir($filename);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.