Anzeige

 C: Wörter, Zeichen, und Zeilen zählen


#1
Hallo,

ich möchte ein Programm schreiben, welches ein Textfile öffnet, alle Chars, Lines und Words zählt.
Geöffnet wird die Datei mit fopen, mit fgetc werden alle Zeichen durchgegangen. Der Chars Counter wird dabei jedes mal erhöht, sollt es zufällig \n sein, wird der Lines Counter auch erhöht.
Beim Word Counter hab ich momentan noch so meine Probleme. Momentan habe ich das mit isspace() realisiert, allerdings zählt der beispielsweise Zahlen auch als Wörter mit. ("Ich bin Hans und bin 8 Jahre alt." Wären 8 Words).

Hier der wichtigste Teil meines C Codes:
C:
do {
n = fgetc (pFile); //in pFile ist das Textfile geöffnet)
c++; //chars
if (n == '\n') l++; //lines
if (isspace(n)) w++; //words
} while (n != EOF);
Wie kann ich das hübscher/besser/effektiver regeln?
 
Zuletzt bearbeitet von einem Moderator:
#2
Hi und Willkommen bei tutorials.de,

Mehrere Leerzeichen hintereinander werden bei dir als mehrere Wörter gezählt.
Da könnte man zB. eine Variable machen, die 1 oder 0 ist,
je nachdem, ob man gerade "in" einem Wort ist.
Auf diese Weise kann man dann auch zeichenweise prüfen, ob es ein gültiges Wort ist.

Fälle, die unterschieden werden müssen:
In einem Wort/nicht
Aktuelles Zeichen ist Buchstabe/Space/Anderes

C++:
char imwort = 0;
do {
    n = fgetc (pFile); //in pFile ist das Textfile geöffnet)
    c++; //chars
    if (n == '\n') l++; //lines

    if(!imwort) //Gerade kein Wort
    {
         if(isalpha(n)) //n ist ein Buchstabe
         {
              w++; //Als Wort(beginn) zählen
              imwort = 1;
         }

         else if(!isspace(n)) //Kein Buchstabe, kein Space
              imwort = 1; //Etwas beginnt, aber es wird nicht gezählt

         //Space brauchen keine Behandlung, wenn man sowieso außerhalb eines Wortes ist
    }

    else //in einem Wort
    {
         if(isspace(n)) //Space beendet das Wort
              imwort = 0;

         else if(!isalpha(n)) //Kein Buchstabe, kein Space, aber im Wort: Irgendwas wie w23x89
         {
              w--; //Wurde beim Anfangsbuchstaben gezählt, ist aber doch kein Wort
         }

         //Buchstaben im Wort brauchen keine Behandlung
    }

} while (n != EOF);
Ich würde mir wegen dem Wortzählen aber keine keine großen Umstände machen,
sogar MS Word zählt Zahlen als Wort :D

Gruß

PS: Bei den Codetags gehört ein / statt \
Habs ausgebessert.
 
#3
Ich würde mir wegen dem Wortzählen aber keine keine großen Umstände machen,
sogar MS Word zählt Zahlen als Wort :D
Wenn das so ist, glaub ich werd ich das auch so stehen lassen!

Ich schau mir auf jeden Fall deinen Code noch genauer an, zum Zwecke des Verständnisses.
Das verschiebe ich aber glaube ich auf morgen, um die Uhrzeit seh ich vor lauter Bäumen den Wald nichtmehr!

Danke schonmal für die sehr rasche Antwort!
 
#4
Okay, also folgendes.

Ich hab mein Programm jetzt etwas erweitert.

Und zwar um die Möglichkeit, einen Suchstring per Parameter einzugeben, welcher in den Files gesucht wird.

Jetzt bin ich schon soweit, dass ich die Files jeweils öffne (ist ja auch keine große Kunst), aber wie ich in den Files jetzt nach dem Suchstring suche und ggf. ausgebe: Ja, in dem eben geöffneten File befindet sich der Suchstring - dafür hab ich absolut keinen Lösungsweg.

Ob mit fgetc, fgets, etc.. Ich google mich dumm und dämlich, aber ich raffs einfach nicht, wie ich die Wörter in der Datei mit dem Suchstring vergleichen soll.

Hat da jemand einen Lösungsansatz?

Vielen Dank
 

cwriter

Erfahrenes Mitglied
#5
Hallo

So vielleicht?
C:
char Suchstring[512];
fgets(Suchstring, 512, STDIN);
FILE* f = fopen("Datei.txt","r");
if(f == NULL) return -1;
char temp[512]; //Wenn die Datei Zeilen hat, die länger als 512 Zeichen sind, erweitern
while(fgets(temp,512,f) != NULL)
{
     if(strstr(temp,Suchstring) != NULL) //Treffer
     {
          printf("Treffer in dieser Zeile: %s",temp);
     }
}
fclose(f);
Ungetestet.


cwriter
 
#6
Danke schön für den Vorschlag schonmal.

Ich poste jetzt einfach mal meinen momentanen Code:

C:
while ((zeile=readdir(verzeichnis)) != NULL){
			printf("Folgende Datei wird durchsucht: %s\n", (*zeile).d_name);
			pFile = fopen("zeile","r");
			while (fgets(compare,512,pFile)!=NULL){
				if (strstr(compare,Suchstring) != NULL){
					printf("Treffer in dieser Datei!");
				}
			}
			n++;
			fclose(pFile);
		}
Vorher öffnet er das momentane Verzeichnis.
Solange zeile ungleich Null ist, also solange noch Dateien im Verzeichnis unbearbeitet sind, gibt er erstmal aus, welche Datei er momentan durchsucht. (Ist nur für mich eine kleine Kontrolle).
Danach öffnet er die Datei, die zeile gerade anzeigt. Solange fgets in der Variable compare noch 512 Zeichen aus dem File pFile bekommt, kontrolliert er per strstr den Inhalt der beiden Variablen compare und Suchstring. Sollten die gleich sein, somit ungleich Null, wird "Treffer.." ausgegeben,. Dann wird noch ein Counter erhöht (nur zur Kontrolle) und das File wieder geschlossen.

Funktionieren tut das trotzdem nicht.

Er kompiliert zwar einwandfrei, wenn ich das Skript allerdings in einem Verzeichnis nach "Josef" suchen lasse, wobei ich genau weiß, dass es ein Txt File gibt, in welchem Josef steht, dann passiert einfach nichts. Mit Ctrl + C kann ich dann den Auftrag abbrechen.

Vorschläge?
 
#7
Erster Fehler:
C++:
pFile = fopen("zeile","r");
muss heißen
C++:
pFile = fopen(zeile,"r");
Sollte deswegen aber nicht endlos warten...hm...

ah:
readdir git keinen String zurück
Da sollte der Compiler aber warnen...
 
#8
Danke für den Hinweis.

Ich hatte zeile sogar anfangs so drinnen stehen, allerdings hat mir der Compiler dabei immer einen Fehler rausgehauen.

Code:
search.c:23:4: Warnung: Übergabe des Arguments 1 von »fopen« von inkompatiblem Zeigertyp [standardmäßig aktiviert]
Jetzt ist mir schon aufgefallen, warum er wartet.

Ich hab fgets(Suchstring,512,STDIN); drinnen stehen. Ergo wartet er natürlich auf die Tastatureingabe.

Wenn ich das mit fgets(Suchstring,512,argv[1]); austausche, kommt eine ähnliche Kompilerfehlermeldung.

E:/ ignoriere ich die Fehler und starte das Programm, kommt es nun zur sofortigen Beendung mit dem Hinweis "Speicherzugriffsfehler".

C ist leider Neuland für mich und muss mir jetzt sehr kurzfristig relativ viel Stoff anschauen.
 

cwriter

Erfahrenes Mitglied
#9
@sheel
readdir() gibt einen String zurück? Ohne an deiner Kompetenz zu zweifeln:
http://pubs.opengroup.org/onlinepubs/7908799/xsh/readdir.html
Ich glaube, es müsste das sein:
C:
pFile = fopen((*zeile).d_name,"r");
Und abstürzen tut es, weil keine Überprüfung da ist, ob die Datei geöffnet werden kann.
C:
if(pFile == NULL)
cwriter

/EDIT: Zu deinem Post: fgets() liest eine Datei, keinen char* []. So sollte es besser gehen:
C:
//Zuerst überprüfen:
if(argc < 3) return;
char Suchstring[512];
strcpy(Suchstring,argv[1]);
 
Zuletzt bearbeitet:
#10
Zum fgets:
Der dritte Parameter muss pFile sein, nicht der Dateiname.

readdir:
Gibt nicht direkt den String zurück (http://linux.die.net/man/3/readdir)
Mach sowas:
C++:
struct dirent *dateiname;
...
while ((dateiname=readdir(verzeichnis)) != NULL){
...
pFile = fopen(dateiname->d_name, "r");
Bzw, was ist die Variable verzeichnis?
Ein String oder DIR?

@cwriter: Oh...das sollte heißen keinen String :D
Einen String hatte er ja schon vorher...
 
#11
C:
fgets(Suchstring, 512, argv[1]);
Das Ding sollte den ersten Parameter einlesen, um dann bei strstr einen Suchstring zum vergleichen zu haben.

Meine ganzen Initialisierungen:
C:
	DIR *verzeichnis;
	FILE *pFile;
	struct dirent *zeile;
	int n=0;
	char *compare;
	char Suchstring[512];
	Suchstring = fgets(Suchstring, 512, argv[1]);
Das Programm momentan:

C:
verzeichnis=opendir(".");
		while ((zeile=readdir(verzeichnis)) != NULL){
			printf("Folgende Datei wird durchsucht: %s\n", (*zeile).d_name);
			pFile = fopen(zeile->d_name,"r");
			while (fgets(compare,512,pFile)!=NULL){
				if (strstr(compare,Suchstring) != NULL){
					printf("Treffer in dieser Datei!");
				}
			}
			n++;
			fclose(pFile);
		}
	
	printf("So viele Einträge im Verzeichnis gibt es: %d\n",n);
	closedir(verzeichnis);
Wahrscheinlich seht ihr als Pro's direkt den Fehler, den ich nicht sehe?!
 

cwriter

Erfahrenes Mitglied
#12
@sheel
Habe ich das k übersehen oder hast du keins geschrieben? Wenn ich es übersehen habe, entschuldige bitte.
Zur Frage: Ein String gäbe doch einen Fehler aus? Oder geht das bei dieser Funktion?

/Edit:
@lordosiris
Was ist denn der Fehler bzw. was geschieht?
Du überprüfst immer noch nicht auf Fehler und bei fgets() als dritten Parameter einen String zu nehmen ist immer noch falsch:
C:
//Zuerst überprüfen:
if(argc < 3) return;
char Suchstring[512];
strcpy(Suchstring,argv[1]);
Was für einen Compiler hast du eigentlich, der das nicht blockt?

cwriter
 
Zuletzt bearbeitet:
#14
Ah stimmt, die Überprüfung.. Entschuldigung..

Hab jetzt ein
C:
if (pFile==NULL) perror ("Error opening file");
			else {
Nach pFile = fopen..; gesetzt.

Wenns also nicht aufgeht kommt Error opening file.

Führe ich das Skript nun aus kommts soweit:
Code:
./search Josef
Folgende Datei wird durchsucht: remove_prefix.sh
Speicherzugriffsfehler
Compiler meckert nurmehr, dass "compare" uninitialisiert werden könnte, obwohl es doch in Verwendung ist?!

Ich verwende Geany unter Ubuntu. war der erste, den ich gefunden habe!
 

cwriter

Erfahrenes Mitglied
#15
Ah, sorry, war klar.
Du nimmst einen char*, der nicht auf NULL gesetzt wurden. Das sollte so gehen (Bin aber nicht sicher. Ich mag Pointer nicht so :p):
C:
char *compare = NULL;
Oder dann gleich einen char array: Sicherer, aber auch nicht so dynamisch:
C:
char compare[512];
Geht aber auch so:
C:
char *compare = new char[512];
Gruss
cwriter
 
Zuletzt bearbeitet:
#16
:* :* :* :* :*

Perfekt************!
Funktioniert nun, er durchsucht die Files und schreibt "TREFFER!" dazu.. So einfach. Und sooo lange hab ich mich damit herumgemüht.

Wahnsinn, willkommen in der fantastischen Welt der EDV!

Übrigens, bald sind die 2Millionen Beiträge voll. Respekt =)
 

Technipion

Erfahrenes Mitglied
#18
Hallo DLRG97,
dieser Thread ist schon 6 Jahre alt. Also prinzipiell geht das (falls die Member noch aktiv sind), aber vielleicht eröffnest du mit deinem Problem einfach einen eigenen Thread? Du kannst ja deinen bisherigen Code posten, deine Gedanken, und die Stelle an der du nicht weiterkommst.

Gruß Technipion
 
Anzeige
Anzeige