Forum: PC-Programmierung Sonderzeichen aus String entfernen


von Elvir È. (elvir)


Lesenswert?

Hallo,

Ich schreibe gerade ein Programm, welches aus einer txt-Datei 
Zeilenweise einen eingelesenen String (Namen) vergleicht und dann 
ausgibt, ob der Name existiert oder nicht.

Hier mein Code:
1
#include <stdio.h>
2
#include <string.h>
3
#include <stdlib.h>
4
#include <limits.h>
5
6
int main(void)
7
{
8
    char content[80];
9
    char name[20], name2[20];
10
    int i=0;
11
    int flag=0;
12
    
13
    FILE *fp;
14
    
15
    fp = fopen("Liste.txt","r");
16
    
17
    if (fp == NULL)
18
    {
19
        printf("Datei konnte nicht geöffnet werden\n Vorgang abgebrochen\n");
20
        fclose(fp);
21
        exit(0);
22
    }
23
    
24
    else
25
    {
26
        printf("Datei wurde korrekt gelesen\n");
27
    }
28
    
29
    
30
    printf("Geben Sie den zu suchenden Namen ein\n");
31
    scanf("%s", name);
32
    
33
    
34
    for (i=0; i<20; i++)
35
    {
36
        fgets(content, 255, fp);
37
        sscanf(name, "%s", name2);
38
    
39
        if(strcmp(name2, content) != 0)
40
        {
41
            flag=0;
42
        }
43
            
44
        else //if(strcmp(name2, content) == 0)
45
        {
46
            flag=1;
47
            break;
48
        }  
49
    }
50
    
51
    printf("Vergleich beendet\n");
52
    
53
    if (flag==0) printf("Der Name existiert NICHT in der Liste\n");
54
    
55
    else printf("Der Name existiert in der Liste\n");
56
     
57
    fclose(fp);
58
    
59
    return 0;
60
}

Die txt-Datei sind so aus:
Anton
Gustav
Karl
Heinrich
Tobias


Das Problem ist, dass in der txt-Datei das Return mit eingelesen wird. 
Wie filtere ich dieses heraus?



Mit freundlichen Grüßen

von Dirk B. (dirkb2)


Lesenswert?

Mit strrchr suchen und ggf. durch '\0' ersetzen.
oder
Selber suchen (for- oder while-Schleife)
oder
kein fgets sondern Zeilen mit fscanf und %s einlesen

Aber noch etwas anderes:
Weißt du wofür die 255 bei fgets(content, 255, fp); steht?
Und wie die mit content zusammen hängt?

von Elvir È. (elvir)


Lesenswert?

Danke für die schnelle Antwort!

Ich habe den Fehler schon gefunden

statt
1
fgets(content, 255, fp);
2
sscanf(name, "%s", name2);

sollte stehen
1
fgets(content, 255, fp);
2
sscanf(content, "%s", name2);

Der String-Compare Befehl filtert sozusagen ja schon das Return heraus.

Zu deiner Frage:
255 ist die Große von content(?). Vorher war das content bei mir 255 
statt 80 und hatte es vergessen im Befehl umzuändern.

Mit freundlichen Grüßen

von Rolf Magnus (Gast)


Lesenswert?

Elvir Ègalo schrieb:
> Vorher war das content bei mir 255 statt 80 und hatte es vergessen im
> Befehl umzuändern.

Und was lernst du daraus?
Um's abzukürzen: Du solltest daraus lernen, daß es nie gut ist, solche 
Zahlen mehrfahch irgendwo hinzuschreiben. Was meinst du, was bei einem 
wirklich komplexen Programm passiert, wenn man da mal so eine Größe 
ändert?
Besser ist es, die Größe genau einmal zu definieren:
1
#define CONTENT_SIZE 255
2
3
[...]
4
5
{
6
    char content[CONTENT_SIZE];
7
8
[...]
9
10
        fgets(content, CONTENT_SIZE, fp);

So kann es nicht passieren, daß die Werte aufgrund einer Änderung 
irgendwann nicht mehr zusammenpassen.

von Dirk B. (dirkb2)


Lesenswert?

Elvir Ègalo schrieb:
> Der String-Compare Befehl filtert sozusagen ja schon das Return heraus.

Nein.

Das mach in diesem Fall das sscanf.
\n ist ein Whitespace und da hört sscanf bei %s mit dem Einlesen auf.
Bzw. überliest es am Anfang.

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
   for (i=0; i<20; i++)
2
    {
3
        fgets(content, 255, fp);
4
        sscanf(content, "%s", name2);
5
...

ist im übrigen auch keine gute Idee.
Gemeint sind die 20 in der for-Schleife.

Woher weißt du, dass in der Datei 20 Namen stehen? Was ist, wenn da mal 
mehr oder weniger Namen enthalten sind?

Fazit: Anstatt einer for-Schleife, geht man anders vor.
Alle Datei-Leseoperationen in C sind so gestaltet, dass man ihren Return 
Wert in der einen oder anderen Form dazu benutzen kann um eine Antwort 
auf die Frage zu erhalten: konnte von der Datei (noch) gelesen werden 
oder nicht?

D.h. man wird die notwendige Schleife so gestalten, dass sie genau über 
diesen Return Wert gesteuert wird. Wenn gelesen werden konnte, dann 
erfolgt ein weiterer Durchgang durch die Schleife.
Bei fgets sieht die Sache so aus, dass fgets einen von NULL 
verschiedenen Wert liefert, wenn gelesen werden konnte und den Wert NULL 
wenn nicht gelesen werden konnte. Die Schleife sieht dann so aus
1
...
2
3
    while( fgets(content, CONTENT_SIZE, fp) != NULL )
4
    {
5
      sscanf(content, "%s", name2);
6
      ....
7
8
    }

Wenn man es ganz genau nimmt, dann müsste man nach Beendigung dieser 
while Schleife noch prüfen, warum diese Schleife abgebrochen wurde, 
warum also fgets nicht mehr lesen konnte. Denn da gibt es ja mehrere 
Möglichkeiten. Eine davon ist, dass die Datei komplett verarbeitet 
wurde, man also bis zum EOF (End Of File) gelesen hat. Ein Aufruf der 
feof()-Funktion klärt das. Liefert er TRUE, dann ist alles in Ordnung. 
Liefert der aber nicht TRUE, dann gab es einen Fehler. Zb. weil jemand 
den USB Stick abgezogen hat, oder die CD einen Lesefehler hatte, oder 
die Netzwerkverbindung zusammengebrochen ist, oder ... Da gibt es viele 
Möglichkeiten, warum fgets den Versuch von einer Datei zu lesen 
abbrechen musste - EOF ist nur eine davon.

von Dirk B. (dirkb2)


Lesenswert?

In diesem Fall (nur ein Eintrag pro Zeile, keine Leerzeichen im Namen, 
durch Whitespace getrennt)
geht auch
1
while( fscanf(fp, "%19s", name2) == 1 )
2
    {
3
      if(strcmp(name2, 
4
      ....
5
6
    }

von ah8 (Gast)


Lesenswert?

1
    fp = fopen("Liste.txt","r");
2
    
3
    if (fp == NULL)
4
    {
5
        printf("Datei konnte nicht geöffnet werden\n Vorgang abgebrochen\n");
6
        fclose(fp);
7
        exit(0);
8
    }


Wenn Dir fopen einen NULL-Pointer zurückgibt und Du anschließend 
versuchst, diesen Pointer mit fclose zu schließen, so könnte Dein 
Programm mit einer segmentation violation abbrechen, wahrscheinlich 
sogar, bevor Du eine Chance hast, die vorhergehende Fehlermeldung zu 
sehen. Denn die geht nach stdout, stdout ist gepuffert und Puffer werden 
bei einem Abbruch meistens nicht mehr geflusht (siehe man fflush). Also, 
schicke Deine Fehlermeldungen mit fprintf nach stderr, dort gehören sie 
hin und es reduziert die Gefahr, dass Dir Meldungen verloren gehen. Vor 
allem aber verzichte auf das fclose an dieser Stelle, es ist mindestens 
konzeptionell falsch. Es kann sein, dass fclose diesen Fehler abfängt, 
das glaube ich aber nicht.

von Rolf Magnus (Gast)


Lesenswert?

ah8 schrieb:
> Also, schicke Deine Fehlermeldungen mit fprintf nach stderr, dort gehören
> sie hin und es reduziert die Gefahr, dass Dir Meldungen verloren gehen.

Und am besten auch gleich noch eine etwas genauere Meldung. Eine 
Fehlermeldung liefert strerror(errno) zurück. Für alles zusammen (also 
die Fehleremeldung plus eigenen Text nach stderr schreiben) gibt's auch 
schon die Funktion perror():
1
    if (fp == NULL)
2
    {
3
        perror("Datei konnte nicht geöffnet werden");
4
        exit(0);
5
    }
Dann wird dein Text ausgegeben, gefolgt von einem Doppelpunkt und dem 
Grund, warum die Datei nicht geöffnet werden konnte.

von Karl H. (kbuchegg)


Lesenswert?

Und wenn man noch ganz lieb ist, dann führt man in der Fehlermeldung 
auch noch an, wie die Datei heißt, die nicht geöffnet werden konnte.

Microsoft hat Millionen Programmierer mit ihrer generischen Meldung "DLL 
konnte nicht geöffnet werden" in die Weißglut getrieben, weil kein 
Mensch wusste, von welcher DLL eigentlich die Rede war. Das ist 
insbesondere dann frustrierend, wenn du einem Kunden am Telefon weiter 
helfen sollst, und der hat nicht mehr als diese Meldung.

von Wolfgang (Gast)


Lesenswert?

Karl Heinz schrieb:
> Und wenn man noch ganz lieb ist, dann führt man in der Fehlermeldung
> auch noch an, wie die Datei heißt, die nicht geöffnet werden konnte.

... und nicht nur den Namen sondern mit voller Pfadangabe.

> Microsoft hat Millionen Programmierer mit ihrer generischen Meldung "DLL
> konnte nicht geöffnet werden" in die Weißglut getrieben ...

Dafür gibt es jetzt beim Abdocken eines "USB-Massenspeichergerätes" die 
in ihrer Präzision kaum zu übertreffende Meldung: "Dieses Gerät wird 
gerade verwendet. Schließen Sie alle Programme oder Fenster, die 
möglicherweise das Gerät verwenden, und wiederholen Sie den Vorgang"

von Rolf Magnus (Gast)


Lesenswert?

Wolfgang schrieb:
> Dafür gibt es jetzt beim Abdocken eines "USB-Massenspeichergerätes" die
> in ihrer Präzision kaum zu übertreffende Meldung: "Dieses Gerät wird
> gerade verwendet. Schließen Sie alle Programme oder Fenster, die
> möglicherweise das Gerät verwenden, und wiederholen Sie den Vorgang"

Eigentlich unglaublich, aber früher war das doch noch schlechter. Da 
wurde nur gemeldet, daß das Gerät gerade nicht beendet werden kann, 
und man soll es doch später nochmal versuchen. Einfach überhaupt kein 
Hinweis darauf, daß es daran liegen könnte, daß ein Programm noch eine 
Datei auf dem Datenträger offen haben hat.
Meine Lieblingsmeldung aus Lotus Notes:
"Beim Öffnen eines Fensters ist ein Fehler aufgetreten."

von Prog R. (daniel_v)


Angehängte Dateien:

Lesenswert?

Passt zwar thematisch nicht ganz hier rein.
Aber meine liebste Fehlermeldung war mal, als ich mich mit einem 
Lenovo-Notebook (Win7) nicht ins WLAN verbinden konnte:

"Die Problembehandlung konnte aufgrund eines Problems nicht gestartet 
werden."

Den Programmierer hätte ich wirklich gerne mal kennengelernt :)
(Hab ich mir sogar aufgehoben)

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.