Ir ao conteúdo
  • Cadastre-se

C Ordenando em ordem alfabética txt


Heyheyhey

Posts recomendados

Boa noite pessoal!

 

Estou tentando desenvolver um módulo, onde o mesmo ordena várias strings presentes em um arquivo .txt (filmes.txt), como por exemplo:

 

LITTLE MAN TATE,1991,JODIE FOSTER

STUCK,2007,STUART GORDON

DANGEROUS GROUND,1997,DARRELL ROODT

ENIGMA,2001,MICHAEL APTED

FLASH GORDON,1980,MIKE HODGES

 

Porém estou tendo dificuldade para fazer isso, são mais de 3000 linhas no arquivo, sendo cada uma delas uma respectiva string.

É necessário "retirar" elas do .txt e então, no final do módulo, gravar elas novamente no .txt em ordem alfabética.

 

Agradeço se puderem ajudar, obrigado!

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Heyheyhey

13 minutos atrás, Heyheyhey disse:

são mais de 3000 linhas no arquivo

Espero que seja 1 string por linha...

Você pode usar a função fgets() para ler uma string num arquivo texto.

Vou inserir uma função e, a partir dela, faça seu programa.

O que você precisaria fazer é, após a leitura, armazenar a tal string em um novo arquivo texto, provavelmente usando o modo "a" na função fopen().

Perceba que para ler, o modo que é usado na função é o "r".

Você decide quantas buscas irá fazer, mas provavelmente um laço de repetição deverá ser usado para tal.

void Busca(char *palavra , char *file){
   char linha[1024] ;
   FILE* fp = fopen(file, "r") ;
   while (fgets(linha , sizeof(linha) , fp )!= NULL)
   {
      if (strstr(linha , palavra )!= NULL)
      {
         printf("%s", linha);
      }
   }
}

 

Link para o comentário
Compartilhar em outros sites

@Lucca Rodrigues Obrigado pelo retorno, eu já tinha feito um pouco, mas minha maior dificuldade é na hora de transportar para o arquivo em ordem alfabética

void ordena (){
	FILE* arquivo = fopen("filmes.txt", "r");
	FILE* temp = fopen("temp.txt", "w");
	char str[3000];
	
	fgets (str, 3000, arquivo); //lê e armazena na string "str" primeira linha
	while(!feof(arquivo)){	//identifica EOF (final do arquivo)	
		
		// Desenvolvimento -> Onde será feito o armazenamento no arquivo "temp.txt" 
      		// em ordem alfabética
			
		fgets (str, 3000, arquivo); //lê e armazena na string "str" as demais linhas
	}
	
  	fclose(arquivo);
  	fclose(tmp);
}

O arquivo onde consta as strings é o "filmes.txt", a ideia era pegar esses arquivos e ir transferindo todos eles em ordem alfabética para o "temp.txt". Após transferi-los para o "temp.txt", iria renomeá-lo para "filmes.txt" e excluir o arquivo "filmes.txt" inicial.

Resumindo minha dúvida principal: Como eu posso pegar todas as strings (presentes no "filmes.txt"), ordena-las em ordem alfabética para transferi-las para um .txt (temp.txt).

Link para o comentário
Compartilhar em outros sites

5 minutos atrás, Heyheyhey disse:

Como eu posso pegar todas as strings (presentes no "filmes.txt"), ordena-las em ordem alfabética para transferi-las para um .txt (temp.txt).

armazene em variaveis os dados, se não entende quando uma string é maior ou menor do que a outra tenho a dizer que use a função strcmp 

A função se comporta assim:

se strcmp(str1, str2) > 0 então str1 > str2 se strcmp(str1, str2) < 0 então str1 < str2 se strcmp(str1, str2) == 0 então str1 == str2

 

O que também implica que:

se strcmp(str1, str2) >= 0 então str1 >= str2 se strcmp(str1, str2) <= 0 então str1 <= str2 se strcmp(str1, str2) != 0 então str1 != str2

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@Heyheyhey Com a string em mãos, armazene em um novo arquivo texto.

Você pode usar a função fprintf() dentro de um laço para armazenar as strings.

Como eu havia dito:

1 hora atrás, Lucca Rodrigues disse:

O que você precisaria fazer é, após a leitura, armazenar a tal string em um novo arquivo texto, provavelmente usando o modo "a" na função fopen().

Caso use o modo "a", se precisar limpar todo o arquivo texto, use o seguinte (considerando que o arquivo texto está na mesma pasta que a main):

fclose(fopen("temp.txt", "w"));

Atente-se a esse exemplo da função fprintf():

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

int main()
{
	FILE *fp;
	double pi = 3.1415;

	setlocale(LC_ALL,"Portuguese");

	fp = fopen("pi.txt", "w");
	fprintf(fp, "Eu sou o PI\n%0.4lf\n", pi);
	fclose(fp);
    return 0;
}

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@Lucca Rodrigues @herbertbahia

3 minutos atrás, Lucca Rodrigues disse:

Com a string em mãos, armazene em um novo arquivo texto.

Você pode usar a função fprintf() dentro de um laço para armazenar as strings.

 

Sim, porém, eu n posso simplesmente armazenar uma string no arquivo, antes de compara-la com todas as outras strings, pois a partir do momento que eu li a primeira string, a mesma pode ser que seja a última que irá constar. Referente a isso que não sei como proceder, devo criar uma matriz com mais de 3000 linhas para armazenar todas as strings do arquivo, e assim conseguindo comparar uma a uma? Creio que nem haja como ter uma matriz com mais de 3000 linhas. É essa a parte que estou empacado.

Link para o comentário
Compartilhar em outros sites

@Heyheyhey

2 minutos atrás, Heyheyhey disse:

a partir do momento que eu li a primeira string, a mesma pode ser que seja a última que irá constar

Não...

Você tem que ler as strings em ordem alfabética, não na ordem que constam no arquivo.

No exemplo de função que eu havia lhe dado, ele busca por uma palavra específica no arquivo.

Faça um laço para buscar as strings em ordem alfabética e armazenar no novo arquivo texto.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, Heyheyhey disse:

Porém estou tendo dificuldade para fazer isso, são mais de 3000 linhas no arquivo, sendo cada uma delas uma respectiva string.

É necessário "retirar" elas do .txt e então, no final do módulo, gravar elas novamente no .txt em ordem alfabética.

 

 

9 minutos atrás, Heyheyhey disse:

O arquivo onde consta as strings é o "filmes.txt", a ideia era pegar esses arquivos e ir transferindo todos eles em ordem alfabética para o "temp.txt". Após transferi-los para o "temp.txt", iria renomeá-lo para "filmes.txt" e excluir o arquivo "filmes.txt" inicial.

 

1 hora atrás, Heyheyhey disse:

LITTLE MAN TATE,1991,JODIE FOSTER

STUCK,2007,STUART GORDON

DANGEROUS GROUND,1997,DARRELL ROODT

ENIGMA,2001,MICHAEL APTED

FLASH GORDON,1980,MIKE HODGES

 

A julgar pelo trecho era um arquivo csv

 

Não faz diferença se tem uma ou 3000 linhas, a grosso modo. Imaginando um máximo de umas 80 letras por linha, vai ter umas 13.000 linhas por megabyte de memória. E é pouco. E é aí que pega, porque você vai querer classificar tudo na memória e gravar depois no outro arquivo. Se não puder manter tudo na memória vai ter que pensar bastante ou vai ficar muito lento.

 

Sua ideia de gravar em outro arquivo e renomear é o que se faz sempre. Talvez apenas ao invés de excluir o original apenas mude para algo como filmes.back.

 

E use opções na linha de comando, super aprovadas desde os anos 70. Se seu programa se chama xx.exe, 

	xx filmes.txt

pega bem e quem vai usar o programa tem menos trabalho, certo? Alias lembro que na linha de comando pode digitar

sort filmes.txt temp.txt
ren filmes.txt filmes.back
ren temp.txt filmes.txt

na linha de comando e seria o seu programa ;) em Windows. No Linux é um pouco deferente.

 

Sobre o programa

int strcmp(const char *str1, const char *str2)

Essa é a função que compara duas strings, devolve -1, 0 ou 1 conforme a comparação

    char *fgets(char *str, int n, FILE *stream)

Essa é a função que lê ima linha do arquivo de entrada

void qsort(
	void *inicio, 
	size_t total, 
	size_t tamanho, 
	int (*compar)(const void *, const void*))

E essa é a função que classifica os caras. Se puder usar. Se não puder acho que aqui por exemplo eu mesmo já postei algumas opções. E outros. 

 

Antes de tudo faça seu programa em torno dos dados. SEMPRE. Aqui eles são muito simples, já que vai usar a linha toda como unidade.

 

Deve decidir como vai tratar isso

        char linha[1300][80]; // 1 megabyte de linhas

um vetor de linhas assim pode ser preguiçoso mas se ninguém reclamar...

 

 

 

 

adicionado 3 minutos depois
17 minutos atrás, Lucca Rodrigues disse:

Caso use o modo "a", se precisar limpar todo o arquivo texto, use o seguinte (considerando que o arquivo texto está na mesma pasta que a main)

 

em uma saída de um programa de classificação nunca imaginaria usar append mode. Apenas "w" está bem.

11 minutos atrás, Heyheyhey disse:

Sim, porém, eu n posso simplesmente armazenar uma string no arquivo, antes de compara-la com todas as outras strings, pois a partir do momento que eu li a primeira string, a mesma pode ser que seja a última que irá constar. Referente a isso que não sei como proceder, devo criar uma matriz com mais de 3000 linhas para armazenar todas as strings do arquivo, e assim conseguindo comparar uma a uma? Creio que nem haja como ter uma matriz com mais de 3000 linhas

 

Pode ir alocando linha a linha e apenas o tamanho que leu em cada uma, mas é uma opção. Ontem eu postei uma função que faz isso, aqui neste forum. De uma olhada. ão sei o que era agora mas está na lista. Ou depois eu vejo. Agora não dá

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

LITTLE MAN TATE,1991,JODIE FOSTER
STUCK,2007,STUART GORDON
DANGEROUS GROUND,1997,DARRELL ROODT
ENIGMA,2001,MICHAEL APTED
FLASH GORDON,1980,MIKE HODGES

Você entendeu o que expliquei? Pra escrever em torno dos dados? Você pode começar por esses aqui em cima e colocar em filmes.txt, na própria linha de comando e ver o que esperar

 

image.png.86fc6bc8b46b1f169b5ad12dba2f6d3f.png

 

O próprio Windows tem sort. E o Linux e o MacOS que é linux também... Então no Windows pode rodar
 

image.png.1b7cec3035760ba9e8eea3edb255083d.png

Como usar os dados na memória?

 

Como eu disse, cabem mais de 13000 linhas por megabyte na memória para um vetor assim

 

    char filmes[17475][60]; // por exemplo, para perto de 1MB

 

mas não é algo assim elegante. 

 

Como o sistema faz isso?

 

Cada programa em C roda com uma estrutura dessas, que é a linha de comando: um vetor de strings que são os parâmetros do programa, certo? E como é declarado isso? Não é segredo algum, em java, em C, em C++,e em muitas linguagens:

    int main( int argc, char**argv); // o popular: 100% dos programas recebem isso

E claro que essa é a maneira elegante e econômica de alocar os filmes

    int      total_de_filmes;
    char**   filmes;

E montar isso a partir do arquivo de entrada. Absurdamente mais econômico, porque cada linha vai ter o tamanho certo, ao invés de 60 ou 80 ou 200 letras por linha.

 

A função que postei ontem

int   insere_na_ordem(int N, int V[], int T)
{	// insere N em V[], V com T elementos
	int pos = 0;
	for (pos = T; pos > 0; pos = pos - 1)
	{	if (V[pos - 1] > N)
			V[pos] = V[pos - 1];
		else break;
	};	// for()
	V[pos] = N; // pos = posicao certa
	return T + 1;
};

Essa função é uma implementação trivial e relativamente didática de um método de classificação, o tal insertion sort, o mais simples de todos. Funciona muito bem no caso em que a entrada é assim, item a item. Simplesmente insere N no Vetor V com T elementos, e devolve T corrigido.

 

É trivial alterar para usar strings ou ponteiros para strings.

 

 

 

adicionado 0 minutos depois
52 minutos atrás, Heyheyhey disse:

Sou novato aqui, não sei mexer muito bem ainda

 

Apenas clica no nome do usuário e vai abrir o perfil do cara. Aí tem um botão marcado explorar conteúdo. Poderia tentar.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

12 horas atrás, Heyheyhey disse:

char str[3000];

 char filmes[17475][60]; // por exemplo, para perto de 1MB

Acho que já viu a diferença certo? char[3000] cabe uma única linha...

 

Resumindo a imagem do que escrevi ontem:

 

image.png.8d69c68596137a8a0b7c9d930919cd06.png

 

A solução "ideal" escrevendo a partir dos dados:

char   entrada[60];
char   saida[60];
int    total_de_filmes;
char** filmes;

// e mais a funcao, alterada
// para inserir uma string em um vetor de strings de tamanho T
// igualzinho ao que o sistema faz para TODO programa em C
int   insere_na_ordem(char* filme, char* filmes[], int T);
  • Abre o arquivo 'entrada', lê todas as linhas e usa a função para gravar no vetor
  • A função já insere na ordem então não precisa fazer mais nada
  • Fecha o arquivo 'entrada' abre o arquivo 'saida'
  • grava todos os filmes na saída e vai liberando a memória de cada um porque não vai usar mais
  • fecha o arquivo de saída
  • hora do lanche

bonus

 

Escreva seu programa aos poucos, e sempre em torno dos dados. Eis a saída de um programa que roda como

    x entrada saida

que grava o conteúdo do arquivo entrada no arquivo saida e mostra na tela as linhas e o tamanho de cada uma. Se não der nenhum parâmetro ele tenta copiar 'filme.txt' em 'temp.txt'

Arquivo de entrada: filmes.txt
Arquivo de saida: temp.txt
[34] LITTLE MAN TATE,1991,JODIE FOSTER
[25] STUCK,2007,STUART GORDON
[36] DANGEROUS GROUND,1997,DARRELL ROODT
[26] ENIGMA,2001,MICHAEL APTED
[30] FLASH GORDON,1980,MIKE HODGES

rodando com o seu exemplo, claro, que eu não ficar digitando ;)

 

O programa

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

int main(int argc, char** argv)
{
	// entrada
	char* arquivo = "filmes.txt";
	char   entrada[80];
	strcpy(entrada, arquivo);
	if (argc > 1) strcpy(entrada, argv[1]);
	printf("Arquivo de entrada: %s\n", entrada);

	// saida
	char*   arquivo_saida = "temp.txt";
	char    saida[80];
	strcpy(saida, arquivo_saida);
	if (argc > 2) strcpy(saida, argv[2]);
	printf("Arquivo de saida: %s\n", saida);

	FILE* F =   fopen(entrada,"r");
	FILE* O =   fopen(saida,"w");

	int N = 60; // maior tamanho de linha
	char linha[60];
	if (F == NULL) return -1;
	while (fgets(linha, N, F) != 0)
	{
		printf("[%2d] %s", strlen(linha), linha);
		fwrite(linha, strlen(linha), 1, O);
	};
	fclose(F);
	return 0;
};
// fim

Trocando o printf() pela chamada a insere() e acertando a criação inicial do vetor de filmes você tem o seu programa

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@arfneto Consegui fazer com que o código funcione, fazendo tudo o que eu esperava hahahaahahha. Aqui está o resultado:

void ordena (int qntfilmes){
	FILE *arquivo = fopen("filmes.txt", "r");
	FILE *tmp = fopen ("tmp.txt", "w");
	char str [300], temp[300], filmes[qntfilmes][300];
	int i, j, cont=0, ret;
	
	fgets (str, 300, arquivo);
	while(!feof(arquivo)){		
		strcpy(filmes[cont], str);
		cont++;
		fgets (str, 300, arquivo);
	}
	
	for (j=0; j<qntfilmes-1; j++){
        for (i=j+1; i<qntfilmes; i++){
            if (strcmp(filmes[j], filmes[i]) > 0){
                strcpy(temp, filmes[j]);
                strcpy(filmes[j], filmes[i]);
                strcpy(filmes[i], temp);
            }
        }
    }
    
    for (i=0; i<qntfilmes; i++){
    	fprintf(tmp,"%s", filmes[i]);
	}
	
	fclose(tmp);
	fclose(arquivo);
	remove("filmes.txt");
	rename("tmp.txt","filmes.txt");
}

int contfilmes (int cont){
	FILE* arquivo = fopen("filmes.txt", "r");
	char c, letra = '\n';
	
	cont=0;
	while(fread (&c, sizeof(char), 1, arquivo)) {
        if(c == letra) {
            cont++;
        }
    } 
    fclose(arquivo);
    return cont;
}

Não consegui utilizar tudo o que vocês me indicaram para que o código ficasse mais eficiente, mas todos os ditos foram de extrema ajuda, muito obrigado!

 

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

17 minutos atrás, Heyheyhey disse:

Não consegui utilizar tudo o que vocês me indicaram para que o código ficasse mais eficiente, mas todos os ditos foram de extrema ajuda, muito obrigado!

 

Muito bom!

 

🤔 Mas era mais esperto já inserir na ordem ao invés de DEPOIS voltar lá e ler tudo de novo e classificar. E eu te mostrei a função :) ...

adicionado 1 minuto depois

E deixou os nomes dos arquivos fixos no programa :( e eu te mostrei como usar parâmetros

Nem tentou ler do usuário?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

3 horas atrás, Heyheyhey disse:

@arfneto Tentei, mas não consegui compreender direito a ideia de como implementar no código...

 

Mas não perguntou nadinha...

int contfilmes (int cont){
	FILE* arquivo = fopen("filmes.txt", "r");
	char c, letra = '\n';
	
	cont=0;
	while(fread (&c, sizeof(char), 1, arquivo)) {
        if(c == letra) {
            cont++;
        }
    } 
    fclose(arquivo);
    return cont;
}

Deixou no código uma função só para abrir o arquivo e contar as linhas?


Mas 

  • se você lê uma a uma as linhas no programa --- e já conta --- para que precisa disso?
  • E se é só pra contar as linhas podia ao menos passar o nome do arquivo como parâmetro...
  • E para que o parâmetro cont?

Deixou isso no programa que entregou 🤔?

 

Considerando

  • o programa que te mostrei, e que já roda copiando o arquivo da entrada para a saída, e aceitando um ou dois arquivos como parâmetro
     
  •  a função que expliquei e mostrei que insere na ordem no vetor, declarada assim
    int   insere_na_ordem(int N, int V[], int T);


    Bastaria mudar essa rotina para usar um vetor de T linhas ao invés de T int. E ela só tem 5 instruções. E a função já colocaria o filme na posição certa.

    Como eu te disse, escreva seu programa em torno dos dados. Para simplificar, eis uma estrutura de dados Filmoteca que serviria:

    typedef struct
    {
    	// a filmoteca vai ser como
    	// todo programa em C
    	// int argc, char** argc
    	int     T; // total de filmes
    	char**  filme; // cada um
    	// mas vamos manter um registro da capacidade maxima
    	// para nao ficar criando um por um mas sim bloco a
    	// bloco
    	int     bloco; // aloca em blocos desse tamanho
    	int     capacidade; // atualizado em multiplos de bloco
    }	Filmoteca;

    Só 4 campos comentadinhos: o total de filmes, quantos cabem na coleção e o ponteiro para os filmes. O bloco é o tanto que aloca por vez, tipo 1000 por vez ao invés de um por um em filme
    E os filmes estão claro em filme[0],filme[1]...filme[T];
    Só precisaria mudar insere() para usar os filmes da Filmoteca... Algo assim:

    int     insere_filme(char* filme, int L, Filmoteca* F);
    // poe 'filme' de tamanho 'L' na filmoteca 'F'

    E eles já entrariam na ordem e depois era só gravar na saída

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

8 horas atrás, Heyheyhey disse:

Não consegui utilizar tudo o que vocês me indicaram para que o código ficasse mais eficiente [[...]]

A princípio, eficiência não é importante:  A discussão é "Ordenando em ordem alfabética txt", ou seja, os procedimentos envolvidos (eficientes e ineficientes) precisa ordenar, não importando os custos. 

 

Uma discussão paralela com todos os resultados, entenda resultado por uma solução, mais envolvente; repleta de números, gráficos, projeções, custo de execução e analise temporal etc, é um caso além.

 

A maioria não tem energia.

 

8 horas atrás, Heyheyhey disse:

Consegui fazer com que o código funcione, fazendo tudo o que eu esperava hahahaahahha.

Ótimo, um resultado satisfatório, inicialmente é tudo de bom. 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...