Regex 使用Perl计算文件或目录中所有文件中所有单词的出现次数

Regex 使用Perl计算文件或目录中所有文件中所有单词的出现次数,regex,perl,perlscript,Regex,Perl,Perlscript,因此,我试图编写一个Perl脚本,它将包含3个参数 第一个参数是输入文件或目录。 如果它是一个文件,它将统计所有单词的出现次数 如果它是一个目录,它将递归地遍历每个目录,并获取这些目录中文件中所有单词的出现次数 第二个参数是一个数字,它将显示出现次数最多的单词的数量。 这将只向控制台打印每个单词的数字 将它们打印到输出文件中,该文件是命令行中的第三个参数 它似乎可以递归地搜索目录,查找文件中出现的所有单词,并将它们打印到控制台 如何将这些打印到输出文件,以及如何接受第二个参数,即数字(例

因此,我试图编写一个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/perl-w
    严格使用;
    搜索(轮班);
    my$input=$ARGV[0];
    my$output=$ARGV[1];
    我的%计数;
    my$file=shift或die“错误:$0文件\n”;
    
    打开我的$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];  
    }
    
    注意事项

    • 您可能应该为文件mimetypes、可读性等添加一个测试
    • 注意unicode
    • 要写入文件,只需将
      >filename.txt
      添加到命令行的末尾;-)
    • 不是标准的核心IO包,我只是在这里做广告和推广;-)(你可以把那部分换掉)
    • 如果您想添加一个
      排序依据
      选项(
      -n--数字
      -a--字母
      等),这可能是一种易于管理的方法

    编辑忽略了根据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调用中的文件列表之后)。当您有一个目录时,您可以使用路径调用search(就像您当前所做的那样),将元素推送到当前数组中,例如

    # 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] );
     }
    
    #输出的项目数
    我的$current=0;
    #对总数(键)进行排序并反转列表,使最高值排在第一位
    #然后浏览一下清单
    对于每个my$t(反向排序{$a$b}键百分比总计)#使用数字
    #比较
    #那种
    {
    #因为total hash的每个值都是一个单词数组,
    #在该数组中循环查找值并打印出数字
    foreach my$w(sort@{$total{$t}
    {
    #打印字数
    打印“$t\n”;
    #增加数字输出
    $current++;
    #如果这是要打印的号码,我们就完成了
    最后一个if($current==$ARGV[1]);
    }
    #如果这是要打印的号码,我们就完成了
    最后一个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);
              }
           }
        }
    
    #检查命令行中是否有三个参数
    如果(@ARGV<3){
    die“错误:必须有三个参数!\n”;
    出口
    }
    #打开文件
    my$file=shift或die“错误:$0文件\n”;
    打开我的$fh、、$output或die“错误:无法打开文件!\n”;
    #对文件中出现最多的单词进行排序并打印它们
    foreach my$str(排序{$count{$b}$count{a}}键%count){
    $high_count++;
    
    如果($high_count Sigh)有几个很好的答案,但这是一个可能的重复:(可能还有其他的)。但这个重复没有被接受的答案,
        # 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);
              }
           }
        }