2011-08-24 22 views
5

soy capaz de encontrar el número de veces que una palabra aparece en un archivo de texto como en Linux podemos utilizar¿cómo puedo encontrar el conteo de varias palabras en un archivo de texto?

cat filename|grep -c tom 

mi pregunta es ¿cómo puedo encontrar el recuento de múltiples palabras como "Tom" y "Joe "en un archivo de texto.

+0

grep cuenta las líneas, no las palabras. ¿Una línea con 'tomtom' en ella cuenta como uno o como dos? – tchrist

+0

¿Qué es exactamente lo que quieres? Múltiples recuentos, uno por cada palabra que especificó? ¿Suma de recuentos para todas las palabras que especificó? ¿Qué es "palabra"? Como ya mencionamos, tu ejemplo cuenta el número de líneas que coinciden con una expresión regular, no con el número de palabras. – GreyCat

Respuesta

3

Puesto que usted tiene un par de nombres, las expresiones regulares es el camino a seguir éste. Al principio pensé que era tan simple como un simple conteo de grep en la expresión regular de Joe o Tom, pero creo que esto no explicaba el escenario en el que Tom y Joe están en la misma línea (o tom y tom para el caso) .

prueba.txt:

tom is really really cool! joe for the win! 
tom is actually lame. 


$ grep -c '\<\(tom\|joe\)\>' test.txt 
2 

Como se puede ver en el archivo test.txt, 2 es la respuesta equivocada, por lo que necesita para dar cuenta de los nombres de estar en la misma línea.

Luego utilicé grep -o para mostrar solo la parte de una línea coincidente que coincide con el patrón donde dio las coincidencias de patrón correctas de tom o joe en el archivo. Luego canalicé los resultados en número de líneas en wc para el recuento de líneas.

$ grep -o '\(joe\|tom\)' test.txt|wc -l 
     3 

3 ... la respuesta correcta! Espero que esto ayude

+2

¿Qué hay de 'tomtom'? – tchrist

+0

Modifiqué un poco la expresión regular para manejar el caso de tomtom. Buen caso de prueba ... gracias por señalarlo. –

+0

El caso de prueba realmente difícil implicaría coincidencias superpuestas en las palabras originales. :) Por ejemplo, si las palabras con las que quería contar son 'cure',' core', 'rely',' lysis', 'island',' land' y 'dish', entonces obtendría 2 hits en cosas como 'inseguramente' y' extravagante' y 3 éxitos en cosas como 'islandish' y' corelysis'. Un enfoque ingenuo los consideraría como una sola pieza. Esto no es divertido con una expresión regular, pero es bastante fácil con N de ellas, una por palabra. – tchrist

2

Ok, así que primero dividir el archivo en palabras, entonces sort y uniq:

tr -cs '[:alnum:]' '\n' < testdata | sort | uniq -c 

Se utiliza uniq:

sort filename | uniq -c 

+0

Palabras, ** no ** líneas. –

+1

Whoops. Para la próxima vez, ¿qué tal si leo la pregunta correctamente? * facepalm * – carlpett

+0

esto (dividir en palabras, seleccionar, contar) hubiera sido mi opción también. cuando sustituyas cosas que no son ': alnum:' a '\ n', es posible que necesites ocuparte de las diferencias de idioma, como en' cat Castilian/*. txt | tr A-Z a-z | tr -cs '[a-záóúíéñ]' '\ n' | ordenar | uniq -c | ordene -n' – mariotomo

1

Uso awk:

{for (i=1;i<=NF;i++) 
    count[$i]++ 
} 
END { 
    for (i in count) 
     print count[i], i 
} 

Esto producirá un conteo de frecuencia de palabras completo para la entrada. tubo de salida aunque a grep para obtener los campos deseados

awk -f w.awk input | grep -E 'tom|joe' 

Por cierto, no es necesario cat en su ejemplo, la mayoría de los programas que actúan como filtros pueden tomar el nombre de archivo como un parámetro; por lo tanto, es mejor utilizar

grep -c tom filename 

si no, hay una fuerte posibilidad de que la gente va a empezar a tirar Useless Use of Cat Award te ;-)

+0

"la mayoría de los programas que actúan como filtros pueden tomar el nombre de archivo como parámetro" ... e incluso cuando no lo hacen, puede seguir utilizando la redirección de entrada (como 'grep -c tom

+0

'grep -c' no busca palabras, por lo tanto, debe buscarlo. –

0

Aquí está uno:

cat txt | tr -s '[:punct:][:space:][:blank:]'| tr '[:punct:][:space:][:blank:]' '\n\n\n' | tr -s '\n' | sort | uniq -c 

ACTUALIZACIÓN

Una solución de script de shell:

#!/bin/bash 

file_name="$2" 
string="$1" 

if [ $# -ne 2 ] 
    then 
    echo "Usage: $0 <pattern to search> <file_name>" 
    exit 1 
fi 

if [ ! -f "$file_name" ] 
then 
    echo "file \"$file_name\" does not exist, or is not a regular file" 
    exit 2 
fi 

line_no_list=("") 
curr_line_indx=1 
line_no_indx=0 
total_occurance=0 

# line_no_list contains loc k the line number loc k+1 the number 
# of times the string occur at that line 
while read line 
do 
    flag=0 
    while [[ "$line" == *$string* ]] 
    do 
    flag=1 
    line_no_list[line_no_indx]=$curr_line_indx 
    line_no_list[line_no_indx+1]=$((line_no_list[line_no_indx+1]+1)) 
    total_occurance=$((total_occurance+1)) 
# remove the pattern "$string" with a null" and recheck 
    line=${line/"$string"/} 
    done 
# if we have entered the while loop then increment the 
# line index to access the next array pos in the next 
# iteration 
    if ((flag == 1)) 
    then 
    line_no_indx=$((line_no_indx+2)) 
    fi 
    curr_line_indx=$((curr_line_indx+1)) 
done < "$file_name" 


echo -e "\nThe string \"$string\" occurs \"$total_occurance\" times" 
echo -e "The string \"$string\" occurs in \"$((line_no_indx/2))\" lines" 
echo "[Occurence # : Line Number : Nos of Occurance in this line]: " 

for ((i=0; i<line_no_indx; i=i+2)) 
do 
    echo "$((i/2+1)) : ${line_no_list[i]} : ${line_no_list[i+1]} " 
done 

echo 
0
  1. La muestra que dio hace no búsqueda de palabras "tom". Contará "átomo" e "fondo" y muchos más.
  2. Grep busca expresiones regulares . expresión regular que coincide con la palabra "tom" o "Joe" es

    \<\(tom\|joe\)\> 
    
0

Usted podría hacer expresión regular,

cat filename |tr ' ' '\n' |grep -c -e "\(joe\|tom\)" 
+0

Su solución incluso representa a Joe y Tom en la misma línea. ¡Bonito! –

+0

@Travis: Sin embargo, erróneamente cuenta 'tomtom' solo una vez, aunque incluso mi abuelo puede ver que hay dos' tom's presentes. – tchrist

0

me olvidó completamente de grep -f:

cat filename | grep -fc names 

AWK solución:

Suponiendo que los nombres están en un archivo llamado names:

cat filename | awk 'NR==FNR {h[NR] = $1;ct[i] = 0; cnt=NR} NR !=FNR {for(i=1;i<=cnt;++i) if(match($0,h[i])!=0) ++ct[i] } END {for(i in h) print h[i], ct[i]}' names - 

Tenga en cuenta que el original grep no busca palabras. p.ej.

$ echo tomorrow | grep -c tom 
1 

Usted necesita grep -w

0
gawk -vRS='[^[:alpha:]]+' '{print}' | grep -c '^(tom|joe|bob|sue)$' 

El programa gawk establece el separador de registro a cualquier cosa no alfabético, por lo que cada palabra va a terminar en una línea separada. Entonces, grep cuenta las líneas que coinciden exactamente con una de las palabras que quieres.

Utilizamos gawk porque el POSIX awk no permite el separador de registro de expresiones regulares.

Por razones de brevedad, se puede reemplazar '{print}' con 1 - de cualquier manera, se trata de un programa awk que simplemente imprime todos los registros de entrada

("es 1 cierto es entonces hacer la acción por defecto, que es {print}??").
0

para encontrar todos los éxitos en todas las líneas

echo "tom is really really cool! joe for the win! 
tom is actually lame." | akw '{i+=gsub(/tom|joe/,"")} END {print i}' 
3 

Este contará "TomTom", como 2 accesos.

Cuestiones relacionadas