Dateien einlesen und vergleichen
-
Hallo, ich habe ein riesen-problem.
Und zwar habe ich ein Programm geschrieben (oder fast), welches anfangs eine Datei namens Test.txt einliest. Diese Datei lese ich mit fgets zeilenweise ein und anschließend sieht sie wenn ich sie ausgebe etwa so aus:1 A_ID=4543 //die 1 steht für Gruppe 1 B_ID=67857 //ID`s könnten auch andere Strings sein C_ID=676 D_ID= E_ID=6788 2 A_ID=67678 //Gruppe 2 beginnt ......
Im weiteren Verlauf des Programmes lese ich noch eine Datei namens aendern.txt ein, welche ungefähr so aussieht:
1 B_id=5 1 D_id=7777
Hierbei handelt es sich um Werte, die in der Test.txt geändert werden müssten. Und zwar muss ich also erst gucken, ob in der Test.txt die Gruppe eins enthalten ist, dann ob eine B_id enthalten ist und wenn ja, dann muss dieser Eintrag geändert werden und in out.inp gespeichert werden. Das mit dem in die Datei schreiben ist auch kein Problem, aber wie kann ich erst kontrollieren ob was geändert werden muss und wie kann ich das dann ändern?
Zumal meine Files alle nur Strings sind? Wer kann helfen?
-
Langsames und sicheres Verfahren.
1 Beide Dateien öffnen.
2 Datei tmp.dat zum schreiben öffen
3 eine Änderungsanweisung aus ändern lesen
4 daraus 3 Teilstrings machen, Orginal behalten
a Teil 1 Gruppe
b Teil 2 Name
c Teil 3 Wert
5 Zeile aus Test.txt lesen
6 daraus 3 Teilstrings machen, Orginal behalten
a Teil 1 Gruppe
b Teil 2 Name
c Teil 3 Wert
7 vergleichen ob Gruppe ändern gleich Gruppe Test ist
a nein Orginal aus test nach out schreiben, dann bei 5 weiter
b ja Name ändern gleich Name Test
a nein Orginal aus test nach out schreiben, dann bei 5 weiter
b ja Orginal aus ändern nach tmp.dat schreiben bei 3 weiter
8 sobald ändern abgearbeitet ist alle 3 dateien schließen, temp.dat nach test.dat Kopieren
fertig.
-
und wie mache ich aus dem String drei Teilstrings?
-
Zum Beispiel mit diesen 2 Funktionen (kann man auch leicht selber schreiben, in dem man das Problem in seine Bestandteile zerlegt und diese Teilprobleme einzeln löst.)
void substr(char * in, char * lowout,char search) { // Teile den String in zwei Teile an der ersten Stelle search und vergiss das Zeichen an der Bruchstelle char *highout; highout=in; while ( ( search != * in ) && ( * in ) ) *lowout++ = *in++; *lowout=0; if (0 != *in)in++; while ( * in ) *highout++= *in++; *highout=0; return; } void StrRmLe(char *s) { // Entferne alle führenden whitespace characters aus einem String int i; int count=0; int len=strlen(s); for (i=0;i<len;i++) { if ( 0 == isspace(s[i])) break; else count++; } if (count > 0) for (i=0;i<len-count+1;i++) s[i]=s[i+count]; return; }
Benutzung:
char *input="1 A_ID=4543"; char part1[80+1]; char part2[80+1]; substr(input,part1,' '); // => in part1 steht "1" in input jetzt " A_ID=4543" StrRmLe(input); // => in input steht jetzt "A_ID=4543" substr(input,part2,'='); // => in part2 steht "A_ID" in input jetzt "4543"
Somit hast du deine 3 Teile und kannst die anderen Aktione durchführen.
PS: falls einer für StrRmLe eine bessere Implementierung weis, ich bin neugierig?
-
int substr(char *quelle, char *ziel, char suche) { char *pos; //Zeichen suchen pos = strchr(quelle, suche); //Zeichen gefunden? if(pos) { //gefundenes Zeichen überschreiben *pos++ = 0; //alles nach dem gefundenen Zeichen kopieren strcpy(ziel, pos); return(0); //Alles OK } else { return(-1); //Suchzeichen nicht gefunden! } }
Bei der zweiten Funktion sollte man anstatt der Schleife zum Kopieren die Funktion strcpy() verwenden oder memcpy() (wenn einem das lieber ist).
-
habe beide codes (von PAD & AJ) mal ausprobiert und habe festgestellt, dass sie sich beide zwar compilieren lassen, jedoch aber beim ausführen einen speicherfehler aufweisen. woran könnte das noch liegen? der debugger hilft mir in diesem fall nicht wirklich weiter.
-
AJ schrieb:
... //gefundenes Zeichen überschreiben *pos++ = 0; ...
genau an der Stelle verabschiedet sich der Debugger... bis dahin funtz es noch. woran könnte das liegen
-
Zeig mal den Aufruf und was du sonst noch mit den verwendeten Strings machst. Ich hoffe du hast nicht die Funktionen einfach mit einem festen String aufgerufen. (z. B. substr("Test=Wert", wert, '=') da der 1. Parameter in der Funktion auch verändert wird, gibt es hier einen Speicherfehler!)
-
char *input="1 A_ID=4543"; char part1[80+1]; char part2[80+1]; sub(input,part1,' '); // => in part1 steht "1" in input jetzt " A_ID=4543" //StrRmLe(input); // => in input steht jetzt "A_ID=4543" //sub(input,part2,'='); // => in part2 steht "A_ID" in input jetzt "4543"
... so rufe ich die Funktion auf
-
natürlich habe ich die funktion von substr in sub umbenannt.
es könnte allerdings auch an:char *input="1 A_ID=4543";
... liegen, vielleicht muss ich das * weglassen und dafür ein vordefiniertes Array nehmen???
-
Korrekt!
Der String ist konstant -> konstant != variabel -> also nicht änderbar
-
Funktion funktioniert zwar, aber nicht richtig. Man beachte beim Orginal verbleibt das Ende des Strings in ersten Parameter, bei der neuen verbleibt dies im zweiten Parameter.
Die Funktion scheint aber schneller zu sein.
Korrektur:
Begin test1 Orginal-Funktion
End test1: 0.256421 Sekunden
Begin test2 Neue Lösung
End test2: 0.332843 Sekunden
Begin test3 Leere Schleife
End test3: 0.070380 Sekunden#define NUM 1000000 void test3(void) {int i; char Peter[129]; char Peter1[129]; APPLTraceB(APPLV1,"test3") for (i=0;i<NUM;i++) { strcpy(Peter,"Dies ist ein Test,hier der zweite Teil"); _substr_(Peter,Peter1,','); //substr, substr_ } APPLTraceE(APPLV1,"test3") }
Eine lösung für die zweite wäre noch viel interessanter!
-
@PAD
Darum ist die "neue" auch schneller, weil nur 1 mal rumkopiert wird (könnte man sich übrigens auch sparen, wenn man es etwas anders verarbeitet -> noch schneller).Die zweite würde ich so lösen:
char *entfWSC(char *text) { char *pos; for(pos = text; *pos && isspace(*pos); ++pos); //kann man sich leider nicht ersparen ;) if(pos != text) strcpy(text, pos); return(text); }
-
Ich musste leider meine Aussage korrigieren die Orginal-Implementierung ist bei mir schneller.
Ergebnisse in Sekunden
Start of applikation part
Begin test1
End test1: 0.256003 Orginal
Begin test2
End test2: 0.329853 Neue Implementierung
Begin test3
End test3: 0.072492 Leer Schleife
Begin test4
End test4: 0.453790 entfWSC
Begin test5
End test5: 0.577858 StrRmLe
End of applikation part
ReturnCode: 0
System ShutdownDas lohnt sich
-
Wie oft hast du es denn probiert?
Möglicherweise bremst strcpy() das ganze etwas aus. Ich wäre aber eigentlich davon ausgegangen, dass es auch nicht viel mehr macht als deine Kopierschleife.
-
Das Testprogramm hat so um die 100 Läufe mit vergleichbaren Ergebnissen unter Win2000 gebracht.
Insgesamt habe ich diese 5 Testfunktionen jede 1 000 000 Mal aufgerufen in MSVC 6.0 release version speed optimiert.Die Funktion test3 sieht wie folgt aus und dient dazu den Overhead zu bestimmen.
Als Timer wird der HIGH-Performance Timer benutztint dummi(char *quelle, char *ziel, char suche) { return 0; } void test3(void) { int i; char Peter[129]; char Peter1[129]; APPLTraceB(APPLV1,"test3") for (i=0;i<NUM;i++) { strcpy(Peter,"Dies ist ein Test,hier der zweite Teil"); dummi(Peter,Peter1,','); } APPLTraceE(APPLV1,"test3") }
-
ich muss aber leider zu geben, dass der Code, bzw. die Funktionen von PAD wesentlich besser funktionieren. Wenn ich bei AJ's Code mir die einzelnen Teile ausgeben lasse, dann bekomme ich nur so ein Schmarn hier:
input : 1 A_ID=166 part1 : ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ 1 A_ID=166 part2 : ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
bei dem Code von PAD klappt es wunderbar (sprich: input wird genau in diese Teile zerlegt), der ist aber schwerer zu verstehen finde ich... Woran könnte das wohl liegen?
Und was ist eigentlich das hier? Da verstehe ich ja nur Bahnhof:#define NUM 1000000 void test3(void) {int i; char Peter[129]; char Peter1[129]; APPLTraceB(APPLV1,"test3") for (i=0;i<NUM;i++) { strcpy(Peter,"Dies ist ein Test,hier der zweite Teil"); _substr_(Peter,Peter1,','); //substr, substr_ } APPLTraceE(APPLV1,"test3") }
Hat das auch irgendwas mit meiner Frage zu tun? Würde mich über einige Kommentare mehr freuen. Danke
-
@Jerry
Wie ist denn der Aufruf bei meiner Funktion und die Ausgabe?
-
So rufe ich deine Funktion auf:
char input[MAX_LEN]="1 A_ID=166234"; char part1[80+1]; char part2[80+1]; printf("\ntestline: %s\n",input); sub(input,part1,' '); entfWSC(input); sub(input,part2,'='); printf("input : %s\n",input); printf("\npart1 : %s\n",part1); printf("part2 : %s\n",part2);
und wenn ich mir nun die Ausgabe angucke kommt genau das raus, was ich eben schon gepostet habe, nur dass "╠" immer ein seltsames Zeichen ist, d.h. dort steht nicht immer diese zahl, sondern ein Zeichen.
-
Seltsam, ich hab grad folgendes
#include <stdio.h> #include <string.h> int substr(char *quelle, char *ziel, char suche); int main(int argc, char **argv) { char text[100] = "Text=Wert"; char wert[20]; substr(text, wert, '='); printf("%s = %s", text, wert); return 0; } int substr(char *quelle, char *ziel, char suche) { char *pos; //Zeichen suchen pos = strchr(quelle, suche); //Zeichen gefunden? if(pos) { //gefundenes Zeichen überschreiben *pos++ = 0; //alles nach dem gefundenen Zeichen kopieren strcpy(ziel, pos); return(0); //Alles OK } else { return(-1); //Suchzeichen nicht gefunden! } }
hiermit compiliert und das Programm ausgeführt. Funktioniert problemlos.