2011-10-09 12 views
5

Soy un novato en Perl y para uno de los deberes que se me ocurrió una solución como esta:¿Cómo se puede hacer esto en forma más Perl

#wordcount.pl FILE 
    # 

    #if no filename is given, print help and exit 
    if (length($ARGV[0]) < 1) 
    { 
      print "Usage is : words.pl word filename\n"; 
      exit; 
    } 

    my $file = $ARGV[0];   #filename given in commandline 

    open(FILE, $file);   #open the mentioned filename 
    while(<FILE>)     #continue reading until the file ends 
    { 
      chomp; 
      tr/A-Z/a-z/;   #convert all upper case words to lower case 
      tr/.,:;!?"(){}//d;   #remove some common punctuation symbols 
      #We are creating a hash with the word as the key. 
      #Each time a word is encountered, its hash is incremented by 1. 
      #If the count for a word is 1, it is a new distinct word. 
      #We keep track of the number of words parsed so far. 
      #We also keep track of the no. of words of a particular length. 

      foreach $wd (split) 
      { 
       $count{$wd}++; 
       if ($count{$wd} == 1) 
       { 
         $dcount++; 
       } 
       $wcount++; 
       $lcount{length($wd)}++; 
      } 
    } 

    #To print the distinct words and their frequency, 
    #we iterate over the hash containing the words and their count. 
    print "\nThe words and their frequency in the text is:\n"; 
    foreach $w (sort keys%count) 
    { 
     print "$w : $count{$w}\n"; 
    } 

    #For the word length and frequency we use the word length hash 
    print "The word length and frequency in the given text is:\n"; 
    foreach $w (sort keys%lcount) 
    { 
     print "$w : $lcount{$w}\n"; 
    } 

    print "There are $wcount words in the file.\n"; 
    print "There are $dcount distinct words in the file.\n"; 

    $ttratio = ($dcount/$wcount)*100;  #Calculating the type-token ratio. 

    print "The type-token ratio of the file is $ttratio.\n"; 

He incluido el comentario de mencionar lo que hace. De hecho, tengo que encontrar el conteo de palabras del archivo de texto dado. La salida del programa anterior se verá así:

The words and their frequency in the text is: 
1949 : 1 
a : 1 
adopt : 1 
all : 2 
among : 1 
and : 8 
assembly : 1 
assuring : 1 
belief : 1 
citizens : 1 
constituent : 1 
constitute : 1 
. 
. 
. 
The word length and frequency in the given text is: 
1 : 1 
10 : 5 
11 : 2 
12 : 2 
2 : 15 
3 : 18 
There are 85 words in the file. 
There are 61 distinct words in the file. 
The type-token ratio of the file is 71.7647058823529. 

A pesar de que con la ayuda de Google puedo capaz de encontrar la solución para mi tarea. Pero, sin embargo, creo que habrá un código más pequeño y conciso que utilizará el poder real de Perl. ¿Alguien puede darme una solución en Perl con muchas menos líneas de código?

+0

De acuerdo con su estado de uso, el nombre del archivo es el segundo argumento. Eso contradice tu código. –

+1

Una sugerencia es: no use abierta explícitamente. Solo usa <>. Perl interpretará cada argumento en ARGV como un nombre de archivo, y <> lo leerá. –

+0

@WilliamPursell: el nombre de archivo Sí es el segundo argumento ... – sriram

Respuesta

9

Aquí hay varias sugerencias:

  • Incluir use strict y use warnings en los scripts de Perl.

  • La validación de su argumento no prueba lo que debería probarse: (1) si hay exactamente 1 elemento en @ARGV, y (2) si ese elemento es un nombre de archivo válido.

  • Aunque hay excepciones para cada regla, generalmente es una buena práctica asignar la devolución de <> a una variable con nombre, en lugar de confiar en $_. Esto es particularmente cierto si el código dentro del bucle que tenga que utilizar una de las construcciones de Perl que también se basa en $_ (por ejemplo, map, grep, o post-fijar for bucles)

    while (my $line = <>){ 
        ... 
    } 
    
  • Perl proporciona una construida -en la función (lc) a cadenas en minúsculas.

  • Está realizando cálculos innecesarios dentro del ciclo de lectura de línea. Si simplemente construye un recuento de palabras, tendrá toda la información que necesita. También tenga en cuenta que Perl ofrece un formulario de una sola línea para la mayoría de sus estructuras de control (for, while, if, etc.), como se ilustra a continuación.

    while (my $line = <>){ 
        ... 
        $words{$_} ++ for split /\s+/, $line; 
    } 
    
  • continuación, puede utilizar la palabra recuentos para calcular la otra información que necesita. Por ejemplo, el número de palabras únicas es simplemente el número de teclas en el hash y el número total de palabras es la suma de los valores de hash.

  • La distribución de longitudes de palabra se puede calcular así:

    my %lengths; 
    $lengths{length $_} += $words{$_} for keys %words; 
    
+0

Los bucles de Postfix son la abominación de la sintaxis n. ° 1 en un lenguaje lleno de abominaciones de sintaxis – Nemo

+0

¡ohhh! Parece tipo de libro de cocina Perl :) Tengo algunas dudas, '$ words {$ _} ++ para split/\ s + /, $ line;' ¿qué está haciendo exactamente esto? No pude entender por qué '$ words {$ _}' usado de esta manera, ¿para qué sirve exactamente '$ _'? – sriram

+0

@GroovyUser Es solo una forma abreviada de 'for (split/\ s + /, $ line) {$ words {$ _} ++}', donde '$ _' es una palabra individual. – FMc

1

Usar hashes como usted es una buena manera de hacerlo. Una forma más fácil de analizar el archivo es utilizar una expresión regular con el indicador/g para leer las palabras de la línea. \w+ significa uno o más caracteres alfanuméricos.

while(<FILE>) 
{ 
    while(/(\w+)/g) 
    { 
     my $wd = lc($1); 
     ... 

    } 
} 
Cuestiones relacionadas