C - Text aus Datei -> Alphabetisch Sortierte Wörter in andere Datei

gutsch

Mitglied
Hi. Habe mal wieder ein Problem:
Ich soll einen Text aus einer Datei (.txt) auslesen und in einer anderen wieder ablegen (alphabetisch sortiert und doppelte raus). Welche Dateien das sein sollen, soll per Parameter in der Konsole übergeben werden. Ein Wort ist eine fortlaufende Folgen von Zeichen A-Z sowie ÖÜÄ und ß. Die Groß- und Kleinschreibung ist hierbei nicht zu berücksichtigen. Alle Nicht-Wörter sind zu
ignorieren.
Per define sollen Obergrenzen für die Anzahl der Wörter bzw die Buchstaben eines Wortes angelegt werden.
Beim Überschreiten der Obergrenzen ist wie folgt vorzugehen:
- Länge eines Wortes ist zu lang : Fehlermeldung ausgeben, Wort ignorieren und mit der Bearbeitung fortfahren (kein Programmende)
- Anzahl der Wörter ist überschritten : Fehlermeldung ausgeben, restlichen Text ignorieren und bisheriges Wörterbuch in zweite Datei schreiben.
Sachen wie strcmp sind dabei nicht zu verwenden (wenn es nicht anders geht, zur Not auch das).

Ja und irgendwie klappt da bei mir beim sortieren / rausschmeißen der Dubletten etwas nicht. Vermutlich ist es eh umständlich geschrieben, aber irgendwie gehen mir gerade auch die Ideen aus :(

Ich poste einfach mal, was ich bisher habe:

Code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define WOERTER 100		// Wörter
#define BUCHSTABEN 25	// Anzahl der Buchstaben


void print(int gez_woerter, int tabelle[WOERTER][BUCHSTABEN+1], FILE *out){

	int w, b = 0;
	
	for (w = 0; w < gez_woerter; w++) {
		if (tabelle[w][0] != '\0'){ 
		
		for (b = 0; tabelle[w][b] != '\0'; b++) {
			fprintf(out, "%c", tabelle[w][b]);
		} fprintf(out, " ");}
	} fprintf(out, "\n\n");
}

void swap(int wort1[], int wort2[]) {
	int dreieck[BUCHSTABEN]; int b;

	for(b = 0; wort1[b] != '\0'; b++)
		dreieck[b] = wort1[b];
		dreieck[b]='\0';
	for(b = 0; wort2[b] != '\0'; b++)
		wort1[b] = wort2[b];
		wort1[b]='\0';
	for(b = 0; dreieck[b] != '\0'; b++)
		wort2[b] = dreieck[b];
		wort2[b]='\0';	
}

// Sortieren
void sort(int tabelle[WOERTER][BUCHSTABEN+1], int *gez_woerter) {
	int w = 0, b = 0, k = 0;
	
	for(w = 0; w < (*gez_woerter); w++) {
		for(b = w + 1; b < (*gez_woerter); b++) {
			if(tabelle[w][0] > tabelle[b][0]) {
				swap(tabelle[w], tabelle[b]); }
			else if(tabelle[w][0] == tabelle[b][0]) {
				for (k = 1; tabelle[w][k] != '\0'; k++) {
					if(tabelle[w][k] > tabelle[b][k]) {
						swap(tabelle[w], tabelle[b]); break; 
					} 
				} 
			}
		}
	}
}

// Main
int main(int argc, char **argv) {
    
	int tabelle[WOERTER][BUCHSTABEN+1];	// 2D Array für die Wörter
	int w=0, b=0, gez_woerter = 0;
	int c;
	FILE *in,*out;	
	
	//int count=1;
	
    // "Genug" Parameter eingegeben? 
    if (argc != 3) {
        printf("Fehler: Ein- und Ausgabedatei muessen uebergeben werden\n\n");
		system("PAUSE");
		return EXIT_FAILURE; }
		
	// Parameter übergeben
    in = fopen (argv[1], "r");
	out = fopen (argv[2], "w");
	
    
    printf("\n\n\n");
	printf("01 - Aufgabe 2 - Woerterbuch\n\n");

	// Testausgabe stdout
	printf("Infile: %s\n", argv[1]); printf("Outfile: %s\n\n", argv[2]);
	
	// Eingabeüberprüfungen
	if ((in == NULL) || (out == NULL)) {					// Können Dateien geöffnet werden?
		printf("Fehler beim Oeffnen der Datei(en)\n");		// Nein? Fehler.
		fclose(in); fclose(out);							// Dateien schließen
		return EXIT_FAILURE;								// Fehler zurückgeben
	} else {
		while ((c = fgetc(in)) != EOF) {
			//printf("\n%d - %c",count++, c);
			// Abfrage, ob es sich um einen der definierten Buchstaben handelt
			if (((c >= 65) && (c <= 90)) /* Großbuchstaben*/ || ((c >= 97) && (c <= 122)) /*Kleinbuchstaben*/ 
			|| (c == 252) /* ü */|| (c == 220) /* Ü */|| (c == 228) /* ä */ || (c == 196) /* Ä */ || (c == 246) /* ö */ || (c == 214) /* Ö */ || (c == 225) /* ß */ ) {

				if ( ((c >= 65) && (c <=90)) || (c == 129) || (c == 132) || (c == 142) ) /* Großbuchstabe? */ c = c + 32;
				
				tabelle[w][b] = c;		// Falls es ein Buchstabe ist, dem 2D Array zuweisen	
				b++;					// Im 2D-Array ein Feld nach rechts
								
			} else {
				//printf("\nKein Zeichen");
				if (tabelle[w][0] != '\0') {	// erstes Feld ein Buchstabe?
					tabelle[w][b] = '\0';		// Dann mit '\0' als letztem Zeichen, die Zeile beenden
					gez_woerter++;		// Zähler für Wörter hochsetzen
					tabelle[w+1][0] = '\0';
					w++;			// Eine Zeile nach unten, für neues Wort...
					b = 0;			// ... und bei 0 (ganz links) anfangen

				} else b = 0;		// Dann neues Wort anlegen - im 2D-Array links beginnend ...
			}
		} 
		if (tabelle[w][0] != '\0') {	
			tabelle[w][b] = '\0';		
			gez_woerter++;		
			w++;			
			b = 0;			
		}
	}

	// Testausgabe gezaehlter Woerter
	fprintf(out, "Gezaehlte Woerter: %d\n", gez_woerter);

	// Testausgabe der "unsortierten" Wörter in eine Datei
	print(gez_woerter, tabelle, out);
	
	// Sortieren
	sort(tabelle, &gez_woerter);

	// Testausgabe der "sortierten" Wörter in eine Datei
	print(gez_woerter, tabelle, out);
	
	// Dateien schließen
    fclose(in); fclose(out);
    
    printf("\n\n\n");
    system("PAUSE");
    return EXIT_FAILURE;
}

Wäre super, wenn mir geholfen werden könnte :)

Beste!
 
Hi

ich sag einfach mal, was mir auffällt:

system PAUSE ... naja. Warum nicht vergleichbares mit getchar oder so?

Beim Prüfen, ob in und out geöffnet werden konnten, darf man innen nicht fclose aufrufen.
Bzw. falls eine der Dateien geöffnet werden konnte, für die schon, aber nicht für NULL.
C++:
if ((in == NULL) || (out == NULL)) {                    // Können Dateien geöffnet werden?
        printf("Fehler beim Oeffnen der Datei(en)\n");      // Nein? Fehler.
        if(in != NULL)
            fclose(in);
        if(out != NULL)
           fclose(out);                            // Dateien schließen
        return EXIT_FAILURE;                                // Fehler zurückgeben
    }
Das else danach ist unnötig, da im if sowieso alles beendet wird.
Man kann den else-Teil einfach so ohne "else" hinschreiben.

Dieser ganze else-block...warum nciht in eine Funktion auslagern?

Statt c>=65 kann man auch c>='A' schreiben. Ist evt. lesbarer
(Achtung, Nicht " " sondern nur ' ')
Gilt aber nicht für die Umlaute, weil anderer Zeichensatz. Da weiter Zahlen verwenden.

Was ist mit den Zu-Voll-Meldungen/Behandlungen?


In print:
Zum printf-en von einzelnen Chars kann man auch fputc verwenden. Ist schneller.
Aber, warum nicht einfach %s statt %c durchschleifen?

In swap:
dreieck braucht BUCHSTABEN+1

Und wenn du strcpy etc. nicht verwenden darfst,
warum keine eigene Funktion machen, statt dreimal den selben Code hinschrieben?


sort kommt später...
 
Danke schonmal. Ich sitze gerade dabei ;) Editiere das dann gleich rein.


EDIT:
Code:
if ((in == NULL) || (out == NULL)) {                    // Können Dateien geöffnet werden?
        printf("Fehler beim Oeffnen der Datei(en)\n");      // Nein? Fehler.
        if(in != NULL)
            fclose(in);
        if(out != NULL)
           fclose(out);                            // Dateien schließen
        return EXIT_FAILURE;                                // Fehler zurückgeben
    }

So übernommen. Dann versucht möglichst viel in Funktionen zu schmeißen und die main schaut nun so aus:

Code:
// Main
int main(int argc, char **argv) {
    
	int tabelle[WOERTER][BUCHSTABEN+1];	// 2D Array für die Wörter
	int w = 0, b =0 , c = 0, gez_woerter = 0;
	FILE *in,*out;	
		
    // "Genug" Parameter eingegeben? 
    if (argc != 3) {
        printf("Fehler: Ein- und Ausgabedatei muessen uebergeben werden\n\n");
		system("PAUSE");
		return EXIT_FAILURE; }
		
	// Parameter übergeben
    in = fopen (argv[1], "r");
	out = fopen (argv[2], "w");
	
    printf("\n\n\n");
	printf("01 - Aufgabe 2 - Woerterbuch\n\n");

	// Testausgabe stdout
	printf("Infile: %s\n", argv[1]); printf("Outfile: %s\n\n", argv[2]);
	
	// Eingabeüberprüfungen
	if ((in == NULL) || (out == NULL)) {                    // Können Dateien geöffnet werden?
        printf("Fehler beim Oeffnen der Datei(en)\n");      // Nein? Fehler.
        if(in != NULL)
            fclose(in);
        if(out != NULL)
           fclose(out);                            // Dateien schließen
        return EXIT_FAILURE;                                // Fehler zurückgeben
    }
    
    // Auslesen
	auslesen(tabelle, in, out, &gez_woerter);
	
	// Testausgabe gezaehlter und unsortierter Wörter
	fprintf(out, "Gezaehlte Woerter: %d\n", gez_woerter);
	print(&gez_woerter, tabelle, out);
	
	// Sortieren
	del(tabelle, &gez_woerter);
	sort(tabelle, &gez_woerter);

	// Testausgabe der "sortierten" Wörter in eine Datei
	print(&gez_woerter, tabelle, out);
	
	// Dateien schließen
    fclose(in); fclose(out);
    
    printf("\n\n\n");
    system("PAUSE");
    return EXIT_FAILURE;
}


Dann die print:
Code:
void print(int *gez_woerter, int tabelle[WOERTER][BUCHSTABEN+1], FILE *out){

	int w, b = 0;
	
	for (w = 0; w < (*gez_woerter); w++) {
		for (b = 0; tabelle[w][b] != '\0'; b++) {
			fprintf(out, "%c", tabelle[w][b]);
		} fprintf(out, " ");
	} fprintf(out, "\n\n");		
}

Habe es nicht hinbekommen, das als %s zu printen, daher erstmal weiter so.

Swap hat sein +1 bekommen:
Code:
void swap(int wort1[], int wort2[]) {
	int dreieck[BUCHSTABEN+1]; int b;

	for(b = 0; wort1[b] != '\0'; b++)
		dreieck[b] = wort1[b];
		dreieck[b]='\0';
	for(b = 0; wort2[b] != '\0'; b++)
		wort1[b] = wort2[b];
		wort1[b]='\0';
	for(b = 0; dreieck[b] != '\0'; b++)
		wort2[b] = dreieck[b];
		wort2[b]='\0';

Und dann noch der Else Block (Eigentlich klar, dass da kein else hin muss... Wald vor lauter Bäume und so):
Code:
// Auslesen
void auslesen(int tabelle[WOERTER][BUCHSTABEN+1], FILE *in, FILE *out, int *gez_woerter) {
	int w = 0, b = 0, c = 0;
	
	while ((c = fgetc(in)) != EOF) {
			
		// Abfrage, ob es sich um einen der definierten Buchstaben handelt
		if (((c >= 65) && (c <= 90)) /* Großbuchstaben*/ || ((c >= 97) && (c <= 122)) /*Kleinbuchstaben*/ 
		|| (c == 252) /* ü */|| (c == 220) /* Ü */|| (c == 228) /* ä */ || (c == 196) /* Ä */ || (c == 246) /* ö */ || (c == 214) /* Ö */ || (c == 223) /* ß */ ) {

			if ( ((c >= 65) && (c <=90)) || (c == 129) || (c == 132) || (c == 142) ) /* Großbuchstabe? */ c = c + 32;
				
			tabelle[w][b] = c;		// Falls es ein Buchstabe ist, dem 2D Array zuweisen	
			b++;					// Im 2D-Array ein Feld nach rechts
								
		} else {
			
			if (tabelle[w][0] != '\0') {	// erstes Feld ein Buchstabe?
				tabelle[w][b] = '\0';		// Dann mit '\0' als letztem Zeichen, die Zeile beenden
				(*gez_woerter)++;		// Zähler für Wörter hochsetzen
				tabelle[w+1][0] = '\0';
				w++;			// Eine Zeile nach unten, für neues Wort...
				b = 0;			// ... und bei 0 (ganz links) anfangen

			} else b = 0;		// Dann neues Wort anlegen - im 2D-Array links beginnend ...
		}
	}
	if (tabelle[w][0] != '\0') {	
			tabelle[w][b] = '\0';		
			(*gez_woerter)++;		
			w++;			
			b = 0;			
		}
}

Das mit den Dezimalzahlen anstelle der Buchstaben habe ich nun erstmal so gelassen. Ist ja kein K.O.-Kriterium.

Und wenn du strcpy etc. nicht verwenden darfst,
warum keine eigene Funktion machen, statt dreimal den selben Code hinschrieben?
Sicher ist mein Stil nicht der schönste, aber wenn es einmal läuft kann ich das ja immer noch anpassen.
 
Zuletzt bearbeitet:
Gerade die Info erhalten, dass string.h nun doch benutzt werden darf.


EDIT:

Code:
/* 
main.c
01 - Aufgabe 2 - Wörterbuch



// Bibliotheken laden
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WOERTER 100		// Wörter
#define BUCHSTABEN 25	// Anzahl der Buchstaben


void print(int *gez_woerter, char tabelle[WOERTER][BUCHSTABEN+1], FILE *out){

	int w, b = 0;
	
	for (w = 0; w < (*gez_woerter); w++) {
		if(tabelle[w][0] != '\0') {
			for (b = 0; tabelle[w][b] != '\0'; b++) {
				fprintf(out, "%c", tabelle[w][b]);
			} fprintf(out, " "); 
		}
	} fprintf(out, "\n\n");		
}

void swap(char wort1[], char wort2[]) {
	char dreieck[BUCHSTABEN+1]; int b;

	for(b = 0; wort1[b] != '\0'; b++)
		dreieck[b] = wort1[b];
		dreieck[b]='\0';
	for(b = 0; wort2[b] != '\0'; b++)
		wort1[b] = wort2[b];
		wort1[b]='\0';
	for(b = 0; dreieck[b] != '\0'; b++)
		wort2[b] = dreieck[b];
		wort2[b]='\0';	
}

void del(char tabelle[WOERTER][BUCHSTABEN+1], int *gez_woerter) {
	int w = 0, b = 0;
	
	for(w = 0; w < (*gez_woerter); w++){
		for(b = w + 1; b < (*gez_woerter); b++){
			if(strcmp(tabelle[w], tabelle[b]) == 0){
				tabelle[w][0] = '\0';
			}
		}
	}
}

// Sortieren
void sort(char tabelle[WOERTER][BUCHSTABEN+1], int *gez_woerter) {
	int w = 0, b = 0, k = 0;
	
	for(w = 0; w < (*gez_woerter); w++) {
		for(b = w + 1; b < (*gez_woerter); b++) {
			if(strcmp(tabelle[w], tabelle[b]) > 0) {
				swap(tabelle[w], tabelle[b]); 
			} 
		}
	}	
}

// Auslesen
void auslesen(char tabelle[WOERTER][BUCHSTABEN+1], FILE *in, FILE *out, int *gez_woerter) {
	int w = 0, b = 0, c = 0;
	
	while ((c = fgetc(in)) != EOF) {
			
		// Abfrage, ob es sich um einen der definierten Buchstaben handelt
		if (((c >= 65) && (c <= 90)) /* Großbuchstaben*/ || ((c >= 97) && (c <= 122)) /*Kleinbuchstaben*/ 
		|| (c == 252) /* ü */|| (c == 220) /* Ü */|| (c == 228) /* ä */ || (c == 196) /* Ä */ || (c == 246) /* ö */ || (c == 214) /* Ö */ || (c == 223) /* ß */ ) {

			if ( ((c >= 65) && (c <=90)) || (c == 129) || (c == 132) || (c == 142) ) /* Großbuchstabe? */ c = c + 32;
				
			tabelle[w][b] = c;		// Falls es ein Buchstabe ist, dem 2D Array zuweisen	
			b++;					// Im 2D-Array ein Feld nach rechts
								
		} else {
			
			if (tabelle[w][0] != '\0') {	// erstes Feld ein Buchstabe?
				tabelle[w][b] = '\0';		// Dann mit '\0' als letztem Zeichen, die Zeile beenden
				(*gez_woerter)++;		// Zähler für Wörter hochsetzen
				tabelle[w+1][0] = '\0';
				w++;			// Eine Zeile nach unten, für neues Wort...
				b = 0;			// ... und bei 0 (ganz links) anfangen

			} else b = 0;		// Dann neues Wort anlegen - im 2D-Array links beginnend ...
		}
	}
	if (tabelle[w][0] != '\0') {	
			tabelle[w][b] = '\0';		
			(*gez_woerter)++;		
			w++;			
			b = 0;			
		}
}

// Main
int main(int argc, char **argv) {
    
	char tabelle[WOERTER][BUCHSTABEN+1];	// 2D Array für die Wörter
	int w = 0, b =0 , c = 0, gez_woerter = 0;
	FILE *in,*out;	
		
    // "Genug" Parameter eingegeben? 
    if (argc != 3) {
        printf("Fehler: Ein- und Ausgabedatei muessen uebergeben werden\n\n");
		system("PAUSE");
		return EXIT_FAILURE; }
		
	// Parameter übergeben
    in = fopen (argv[1], "r");
	out = fopen (argv[2], "w");
	
    printf("\n\n\n");
	printf("01 - Aufgabe 2 - Woerterbuch\n\n");

	// Testausgabe stdout
	printf("Infile: %s\n", argv[1]); printf("Outfile: %s\n\n", argv[2]);
	
	// Eingabeüberprüfungen
	if ((in == NULL) || (out == NULL)) {                    // Können Dateien geöffnet werden?
        printf("Fehler beim Oeffnen der Datei(en)\n");      // Nein? Fehler.
        if(in != NULL)
            fclose(in);
        if(out != NULL)
           fclose(out);                            // Dateien schließen
        return EXIT_FAILURE;                                // Fehler zurückgeben
    }
    
    // Auslesen
	auslesen(tabelle, in, out, &gez_woerter);
	
	// Testausgabe gezaehlter und unsortierter Wörter
	fprintf(out, "Gezaehlte Woerter: %d\n", gez_woerter);
	print(&gez_woerter, tabelle, out);
	
	// Sortieren
	del(tabelle, &gez_woerter);
	sort(tabelle, &gez_woerter);

	// Testausgabe der "sortierten" Wörter in eine Datei
	print(&gez_woerter, tabelle, out);
	
	// Dateien schließen
    fclose(in); fclose(out);
    
    printf("\n\n\n");
    system("PAUSE");
    return EXIT_FAILURE;
}

So ist es bisher. Zumindest macht er mit der Testdatei, was er machen sollte. Aber fertig ist es ja nun noch nicht

EDIT: Muss da nun noch was abfangen, falls es zu viele Wörter / Buchstaben werden
 
Zuletzt bearbeitet:
Ich komme gerade nicht weiter. So weit ist es:
...

Zusammengefasst muss ich dann erstmal noch:
# Gezählte Wörter Fehler beheben << behoben
# Buchstaben Obergrenze
# Extra Funktion << sollte passen



Jemand eine Idee wie ich das mit der Buchstaben Obergrenze lösen kann?!
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück