Contar palavras de um arquivo

1. Contar palavras de um arquivo

Rafael L.
SrKon

(usa Manjaro Linux)

Enviado em 20/04/2021 - 14:11h

Não estou conseguindo contar as palavras de um arquivo(pode incluir as preposições, mas se uma alma caridosa quiser contribuir para fazer sem as preposições, fico grato):
O que tenho até o momento é isso:
#include <stdio.h>
#include <string.h>

int main()
{
FILE *arq;
int qntdCarac = 0, qntdLinhas = 0, qntdPalavras = 0;
char c;
char *sub, conteudo[100];
int a = 0, b = 0, C = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
int i = 0, j = 0, k = 0, l = 0, m = 0, n = 0 ,o = 0, p = 0;
int q = 0, r = 0, s = 0, t = 0, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0;

arq = fopen("doc.txt", "r");

while((c = getc(arq)) != EOF)
{
qntdCarac++;
if(c == '\n')
{
qntdLinhas++;
} else if(c == ' ')
{
qntdPalavras++;
}
switch(c)
{
case 'a':
a++;
break;
case 'b':
b++;
break;
case 'c':
C++;
break;

case 'd':
d++;
break;
case 'e':
e++;
break;
case 'f':
f++;
break;
case 'g':
g++;
break;
case 'h':
h++;
break;
case 'i':
i++;
break;
case 'j':
j++;
break;
case 'k':
k++;
break;
case 'l':
l++;
break;
case 'm':
m++;
break;
case 'n':
n++;
break;
case 'o':
o++;
break;
case 'p':
p++;
break;
case 'q':
q++;
break;
case 'r':
r++;
break;
case 's':
s++;
break;
case 't':
t++;
break;
case 'u':
u++;
break;
case 'v':
v++;
break;
case 'w':
w++;
break;
case 'x':
x++;
break;
case 'y':
y++;
break;
case 'z':
z++;
}
====== ESTA É A PARTE DE CONTAR AS PALAVRAS ======
sub = strtok(arq, " .!,");
while(sub != NULL)
{
sub = strtok(NULL, " ");
qntdPalavras++;
}
======================
}

printf("Qntd de caracteres : %d\nqntd de linhas: %d\n"
"qntd de palavras = %d\n\n", qntdCarac-qntdLinhas, qntdLinhas+1, qntdPalavras+1);
printf( "a = %d, b = %d, c = %d, d = %d,\n e = %d, f = %d, g = %d, h = %d,\n "
"i = %d, j = %d, k = %d, l = %d,\n m = %d, n = %d ,o = %d, p = %d,\n "
"q = %d, r = %d, s = %d, t = %d,\n u = %d, v = %d, w = %d, x = %d,\n "
"y = %d, z = %d",
a, b, C, d, e, f, g, h, i, j, k, l, m, n ,o, p, q, r, s, t, u, v, w, x, y, z );


fclose(arq);

return 0;
}




  


2. Re: Contar palavras de um arquivo

Samuel Leonardo
SamL

(usa XUbuntu)

Enviado em 20/04/2021 - 17:25h

Sugiro que você estude pelo menos análise léxica e máquinas de estados, pois, é justamente com algo assim que você poderá escrever um código mais limpo e usando menos comandos.

Por exemplo:
Com um analisador léxico, você pode transformar cada palavra como um token do tipo identificador, e ir contando:

/**
* @file minilexer.c
* @author Samuel Leonardo
* @brief Mini analisador léxico de uma string
* @version 0.1
* @date 2021-04-20
*
* @copyright Copyleft (c) 2021
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( ) {
//modifique esta string para ver se o analisador funciona
//observe que, só coloquei o caractere ' ' (espaço) como separador das palavras
//você pode modificar facilmente para outros caracteres como o \n \t etc e tal
//NOTA: também não coloquei para ignorar pontuaçlão, por isso,
//algo como "aqui," é encarado como uma palavra
const char * str = "String teste Com Char MAIUSCULOS!";
//estado do analisador léxico
int estado = 0;
//posição do caractere atual
int p = 0;
int tamanho = strlen(str);
int qtdePalavras = 0;
while (str[p]) {
//estado de lendo um caractere
if (estado == 0) {
if (str[p] != ' ') {
//vai para estado de lendo identificador (palavra sem espaço)
estado = 1;
}
else {
// move a posição do caractere atual
p++;
}
}
// lendo um identificador
else if (estado == 1) {
int inicio = p;
int fim = p + 1;
while (str[fim] && str[fim] != ' ') {
fim++;
}

//verifica agora se o fim NÃO é o char '\0' ou um ' ' (espaço)
if (str[fim] == '\0' || str[fim] == ' ') {
// se estamos aqui, é de se supor que estamos lendo um caractere do alfabeto
// seria mais interessante ter verificado isso no if daqui
// agora, incrementa o contador de palavras
qtdePalavras++;
}

// depois, posiciona o contador de posição na posição do fim
p = fim;

// volta ao estado de lendo caractere
estado = 0;
}
}

printf("Frase: %s \n\tem %d palavras\n", str, qtdePalavras);
return 0;
}

Os conceitos utilizados nesse programa acima são:
1-análise léxica
2-máquina de estados finitos
Daria até para desenhar num papel como funciona a transição de estados, fica até mais fácil de ler assim. Mas prefiro não fazer isso por questão de tempo.

____________________________________________
https://nerdki.blogspot.com/ acessa aí vai lá, é grátis!
Capeta (demo) do meu trabalho:
https://github.com/cpusam



3. Re: Contar palavras de um arquivo

Mauricio Ferrari
mauricio123

(usa Slackware)

Enviado em 21/04/2021 - 13:24h


Quer um contador de palavras:

alias wordcont="awk '{for(n=1;n<=NF;n++) {if(\$n~/[[:alpha:]]{1,}/)c++;}}END{print \"Palavras: \"c\"\\nLinhas: \"NR}'"

Adaptei para um aliases: créditos para msoliver.

___________________________________________________________
Conhecimento não se Leva para o Túmulo.
https://github.com/MauricioFerrari-NovaTrento



4. Re: Contar palavras de um arquivo

Rafael L.
SrKon

(usa Manjaro Linux)

Enviado em 21/04/2021 - 14:50h


SamL escreveu:

Sugiro que você estude pelo menos análise léxica e máquinas de estados, pois, é justamente com algo assim que você poderá escrever um código mais limpo e usando menos comandos.

Por exemplo:
Com um analisador léxico, você pode transformar cada palavra como um token do tipo identificador, e ir contando:

/**
* @file minilexer.c
* @author Samuel Leonardo
* @brief Mini analisador léxico de uma string
* @version 0.1
* @date 2021-04-20
*
* @copyright Copyleft (c) 2021
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( ) {
//modifique esta string para ver se o analisador funciona
//observe que, só coloquei o caractere ' ' (espaço) como separador das palavras
//você pode modificar facilmente para outros caracteres como o \n \t etc e tal
//NOTA: também não coloquei para ignorar pontuaçlão, por isso,
//algo como "aqui," é encarado como uma palavra
const char * str = "String teste Com Char MAIUSCULOS!";
//estado do analisador léxico
int estado = 0;
//posição do caractere atual
int p = 0;
int tamanho = strlen(str);
int qtdePalavras = 0;
while (str[p]) {
//estado de lendo um caractere
if (estado == 0) {
if (str[p] != ' ') {
//vai para estado de lendo identificador (palavra sem espaço)
estado = 1;
}
else {
// move a posição do caractere atual
p++;
}
}
// lendo um identificador
else if (estado == 1) {
int inicio = p;
int fim = p + 1;
while (str[fim] && str[fim] != ' ') {
fim++;
}

//verifica agora se o fim NÃO é o char '\0' ou um ' ' (espaço)
if (str[fim] == '\0' || str[fim] == ' ') {
// se estamos aqui, é de se supor que estamos lendo um caractere do alfabeto
// seria mais interessante ter verificado isso no if daqui
// agora, incrementa o contador de palavras
qtdePalavras++;
}

// depois, posiciona o contador de posição na posição do fim
p = fim;

// volta ao estado de lendo caractere
estado = 0;
}
}

printf("Frase: %s \n\tem %d palavras\n", str, qtdePalavras);
return 0;
}

Os conceitos utilizados nesse programa acima são:
1-análise léxica
2-máquina de estados finitos
Daria até para desenhar num papel como funciona a transição de estados, fica até mais fácil de ler assim. Mas prefiro não fazer isso por questão de tempo.

____________________________________________
https://nerdki.blogspot.com/ acessa aí vai lá, é grátis!
Capeta (demo) do meu trabalho:
https://github.com/cpusam


Eu agradeço a sua ajuda. Gostaria que explicasse o
str[fim] && str[fim]
,
não entendi porque repetir esse comando, para mim é a mesma coisa.

Não é redundante/ desnecessário colocar
estado = 0;


Eu preciso fazer com que o código repita isso até que o arquivo acabe. Usei uma função, mas não funcionou. Usei, também, outro laço colocando isso dentro dele, nada. Então algumas dica de como repetir para várias linhas?


5. Re: Contar palavras de um arquivo

Rafael L.
SrKon

(usa Manjaro Linux)

Enviado em 21/04/2021 - 14:54h


mauricio123 escreveu:


Quer um contador de palavras:

alias wordcont="awk '{for(n=1;n<=NF;n++) {if(\$n~/[[:alpha:]]{1,}/)c++;}}END{print \"Palavras: \"c\"\\nLinhas: \"NR}'"

Adaptei para um aliases: créditos para msoliver.

___________________________________________________________
Conhecimento não se Leva para o Túmulo.
https://github.com/MauricioFerrari-NovaTrento


Olá,
Nunca estudei isso:
alias wordcont="awk


Disso, entendi apenas o IF:
{if(\$n~/[[:alpha:]]{1,}/)c++;}}END


Isso é uma variável?
\"NR}'"



6. Re: Contar palavras de um arquivo

Samuel Leonardo
SamL

(usa XUbuntu)

Enviado em 21/04/2021 - 17:51h

SrKon escreveu:


SamL escreveu:

Sugiro que você estude pelo menos análise léxica e máquinas de estados, pois, é justamente com algo assim que você poderá escrever um código mais limpo e usando menos comandos.

Por exemplo:
Com um analisador léxico, você pode transformar cada palavra como um token do tipo identificador, e ir contando:

/**
* @file minilexer.c
* @author Samuel Leonardo
* @brief Mini analisador léxico de uma string
* @version 0.1
* @date 2021-04-20
*
* @copyright Copyleft (c) 2021
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( ) {
//modifique esta string para ver se o analisador funciona
//observe que, só coloquei o caractere ' ' (espaço) como separador das palavras
//você pode modificar facilmente para outros caracteres como o \n \t etc e tal
//NOTA: também não coloquei para ignorar pontuaçlão, por isso,
//algo como "aqui," é encarado como uma palavra
const char * str = "String teste Com Char MAIUSCULOS!";
//estado do analisador léxico
int estado = 0;
//posição do caractere atual
int p = 0;
int tamanho = strlen(str);
int qtdePalavras = 0;
while (str[p]) {
//estado de lendo um caractere
if (estado == 0) {
if (str[p] != ' ') {
//vai para estado de lendo identificador (palavra sem espaço)
estado = 1;
}
else {
// move a posição do caractere atual
p++;
}
}
// lendo um identificador
else if (estado == 1) {
int inicio = p;
int fim = p + 1;
while (str[fim] && str[fim] != ' ') {
fim++;
}

//verifica agora se o fim NÃO é o char '\0' ou um ' ' (espaço)
if (str[fim] == '\0' || str[fim] == ' ') {
// se estamos aqui, é de se supor que estamos lendo um caractere do alfabeto
// seria mais interessante ter verificado isso no if daqui
// agora, incrementa o contador de palavras
qtdePalavras++;
}

// depois, posiciona o contador de posição na posição do fim
p = fim;

// volta ao estado de lendo caractere
estado = 0;
}
}

printf("Frase: %s \n\tem %d palavras\n", str, qtdePalavras);
return 0;
}

Os conceitos utilizados nesse programa acima são:
1-análise léxica
2-máquina de estados finitos
Daria até para desenhar num papel como funciona a transição de estados, fica até mais fácil de ler assim. Mas prefiro não fazer isso por questão de tempo.

____________________________________________
https://nerdki.blogspot.com/ acessa aí vai lá, é grátis!
Capeta (demo) do meu trabalho:
https://github.com/cpusam




Eu agradeço a sua ajuda. Gostaria que explicasse o
str[fim] && str[fim]
,
não entendi porque repetir esse comando, para mim é a mesma coisa.

Vou supor que você esteja falando da linha do while (str[fim] && str[fim] != ' ')
Esse comqando ele quer dizer o seguinte: ENQUANTO str[fim] for diferente de zero E str[fim] for diferente do caractere espaço execute o while
Então, é seguinte, se por exemplo, o valor numérico do caractere str[fim] for igual ao '\0', que é o caractere de fim de string, que tem valor igual a zero, dai o while acabaria porque já leu toda a string e a variável fim seria igual ao tamanho da string. Mas observe que, se por acaso NÃO ler um caractere igual a zero (ou '\0'), dai pode ser que vamos ler um espaço na string, e se por acaso for um espaço? Daí, o str[fim] != ' ' vai ser falso, pois na posição fim na str tem um espaço.
Por isso, quando sair do while, nós vamos poder ter duas situações distintas:
1-ou na posição str[fim] tem um caractere nulo (caractere '\0')
2-ou na posição str[fim] tem um caractere espaço
A situação 1 acima só acontece com a ÚLTIMA palavra, enquanto que a situação 2 acontece quando é da primeira até a penúltima palavra na str.
Por isso, no if mais abaixo, eu coloquei um OU (operador ||) pra justamente verificar essas duas situações e depois incrementar o contador de palavras.


Não é redundante/ desnecessário colocar
estado = 0;


Faltou você dizer em quais linhas você tá falando, mas vou explicar uma a uma.
Numa máquina de estados finitos, sempre é preciso dizer qual o estado inicial da máquina, o estado que ela deve começar trabalhar.
Então, na linha int estado = 0; (antes do while(str[p]), eu estou indicando: começe a máquina com estado inicial sendo o 0.
Agora observe o seguinte, dentro do while, exatamente nos if's, existe um estado = 0 dentro do if (estado == 1), sabe por quê? Porque como esses dois if's, o if (estado == 0) e o else if (estado == 1), estão dentro do while (str[p]). Ou seja, quando eu faço estado = 1 dentro do if (estado == 0), eu estou mudando o fluxo do processamento do while pra dentro do segundo if (o else if (estado == 1), compreende? E dentro do else if (estado == 1), eu novamente mudo o fluxo de processamento pra dentro do primeiro if, ou seja, coloco estado = 0 pra ai sim na próxima vez que o while(str[p]) voltar executar, ele entra dentro do primeiro if (estado == 0).


Eu preciso fazer com que o código repita isso até que o arquivo acabe. Usei uma função, mas não funcionou. Usei, também, outro laço colocando isso dentro dele, nada. Então algumas dica de como repetir para várias linhas?

É bem simples, vou te explicar o processo, eu não quis fazer o programa lendo do arquivo pra que você pudesse pensar sozinho, mas vou explicar um passo a apasso mais mastigado.

Então, você tem que saber visualizar um arquivo de texto mentalmente. Por exemplo, imagina o seguinte, você abriu um arquivo de texto num editor, dai o que o editor faz? Coloca a posição do cursor no primeiro caractere da primeira linha (aquele palitinho branco que aparece piscando).
Então, é só imaginar que, a str do meu programa seja o arquivo de texto com todo conteúdo e o str[p] seja o caractere atual.
Sendo assim, o str[0] é o primeiro caractere da primeira linha (o caractere mais a esquerda da linha 1)
Se tu olhar bem no meu programa, ele trata algumas situações comuns, por exemplo: fim da string é o '\0' e o fim do arquivo seria o EOF, ou seja, é o mesmo que dizer:
while (str[p])
equivale a isso abaixo
while (!feof(arquivoTxt))

Mas e você pode pergunatr: e como faço pra ler do arquivo?
Eu digo: simples, use fgetc:
exemplo:

//abra um arquivo de texto aqui, chame de arquivoTxt
//no loop de caracteres
while (!feof(arquivoTxt)) {
int caractere = fgetc(arquivoTxt);
}


fgetc cada vez que é executada ele lê o caractere do arquivo e retorna ele. Só que o seguinte, quando ela faz isso, o cursor do arquivoTxt vai ser movido pro próximo caractere. Por isso, se tu executar uma vez, vai ler o primeiro caractere e mover o curso do arquivoTxt pra direita num txt. Depois, executa de novo, retrona o caractere e move o cursor novamente, depois faz de novo isso até o fim do arquivo.
Quando chega no fim do arquvio, o while(!feof(arquivoTxt)) vai ser falso e quebrar o loop.

Então, pra resumir:
-ao invés de usar str[p] ou str[fim] no meu programa, você deve substituir pelo caractere lido com fgetc do arquivoTxt. Mas observe que não será fácil fazer isso, porque dentro do if (estado == 1) existe outro while que lê caracteres da str, ou seja, tem que colocar outro fgetc pra ler o próximo caractere de dentro do arquivoTxt.

____________________________________________
https://nerdki.blogspot.com/ acessa aí vai lá, é grátis!
Capeta (demo) do meu trabalho:
https://github.com/cpusam



7. Re: Contar palavras de um arquivo

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 22/04/2021 - 02:44h


SrKon escreveu:


mauricio123 escreveu:
Quer um contador de palavras:
alias wordcont="awk '{for(n=1;n<=NF;n++) {if(\$n~/[[:alpha:]]{1,}/)c++;}}END{print \"Palavras: \"c\"\\nLinhas: \"NR}'"
Adaptei para um aliases: créditos para msoliver.


Olá,
Nunca estudei isso:
alias wordcont="awk


Disso, entendi apenas o IF:
{if(\$n~/[[:alpha:]]{1,}/)c++;}}END


Isso é uma variável?
\"NR}'"


Boa noite, SrKon.
alias, é um apelido de um comando
No Debian e derivadas, pode ser colocado em
~/.bashrc, ou outro arquivo, desde que o ~/.bashrc faça referência ao mesmo.
Veja alias --help.
-----------------------------------------------------------------------------------------------------
O comando:
awk '{for(n=1;n<=NF;n++) {if($n~/[[:alpha:]]{1,}/)c++;}}END{print "Palavras: "c"\nLinhas: "NR}' arquivo.txt
for(n=1;n<=NF;n++) =» Um laço "pegando" cada campo, NF é uma variável do awk, Number Field => "Número do Campo"
{if($n~/[[:alpha:]]{1,}/)c++;}} =» Se, o campo tem uma ou mais letras, c++ (conta uma palavra)
END{print "Palavras: "c"\nLinhas: "NR}' =» Printa a qtdd de palavras e a qtdd de linhas.
NR => Número de Registros.
______________________________________________________________________
Att.: Marcelo Oliver
______________________________________________________________________