track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Progressive schrieb: Wenn ich das richtig verstehe: Würde sich hinter dem String zufälliger Inhalt befinden, würde zwischen diesen 0x00 stehen und der string dann ohnehin nicht mehr "weitergelesen" werden ?
Ja, genau. Was die Spezialitäten des Kompilierens und die C++- Besonderheiten angeht, habe ich keine Ahnung. Da müssen Dir die anderen weiter helfen ... LG, track
|
Progressive
(Themenstarter)
Anmeldungsdatum: 22. Januar 2016
Beiträge: 166
|
track schrieb: Progressive schrieb: Wenn ich das richtig verstehe: Würde sich hinter dem String zufälliger Inhalt befinden, würde zwischen diesen 0x00 stehen und der string dann ohnehin nicht mehr "weitergelesen" werden ?
Ja, genau. Was die Spezialitäten des Kompilierens und die C++- Besonderheiten angeht, habe ich keine Ahnung. Da müssen Dir die anderen weiter helfen ... LG, track
Nützlich zu wissen. Danke dafür!
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Halt, ich muss mich da etwas korrigieren. Progressive schrieb: Wenn ich das richtig verstehe: Würde sich hinter dem String zufälliger Inhalt befinden, würde zwischen diesen 0x00 stehen und der string dann ohnehin nicht mehr "weitergelesen" werden ?
Ja, genau.
Nein, eben nicht genau. Selbstverständlich kannst Du byteweise auch auf die Zeichen außerhalb Deines Strings zugreifen. Beispiel: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #include<stdio.h>
#include<string.h>
int main() {
int i;
char string[] = "abcdefg";
for(i=0; i<8; i++) {
printf("Zeichen %x [%c]\n", string[i], string[i]);
}
strcpy(string,"XY");
for(i=0; i<8; i++) {
printf("Zeichen %x [%c]\n", string[i], string[i]);
}
return 0;
}
|
zeigt schön, was da im Speicher steht: track@track:~$ ./string_test
Zeichen 61 [a] # 1. Text
Zeichen 62 [b]
Zeichen 63 [c]
Zeichen 64 [d]
Zeichen 65 [e]
Zeichen 66 [f]
Zeichen 67 [g] # .. bis hierher
Zeichen 0 []
Zeichen 58 [X] # 2. Text
Zeichen 59 [Y] # .. bis hierher
Zeichen 0 []
Zeichen 64 [d] # Rest von früher bleibt stehen ...
Zeichen 65 [e]
Zeichen 66 [f]
Zeichen 67 [g]
Zeichen 0 [] Spätestens, wenn Du die 0x00 mit "Z" vergleichst, dann gibt es da einen Unterschied ! LG, track
|
Progressive
(Themenstarter)
Anmeldungsdatum: 22. Januar 2016
Beiträge: 166
|
Oo Was ist "Z" ? Gibt es eine elegante Möglichkeit einen string zu "leeren", bevor er wiederverwendet wird ?
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Progressive schrieb: Was ist "Z" ?
... da war ich jetzt mal ganz "intuitiv" von Deinem Vergleich ganz zu Anfang des Strangs ausgegangen. Wenn Du Dein | string[0] == 'X' && string[1] == 'Y' && string[2] == 'Z'
|
auf meinen 2. Text anwendest, dann vergleicht er am Stringende 0x00 mit "Z", und die sind verschieden. Gibt es eine elegante Möglichkeit einen string zu "leeren", bevor er wiederverwendet wird ?
Probier es doch selber, wie ein leerer String abgelegt wird: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | #include<stdio.h>
#include<string.h>
int main() {
int i;
char string[] = "abcdefg";
for(i=0; i<8; i++) {
printf("Zeichen %x [%c]\n", string[i], string[i]);
}
printf("\n");
strcpy(string,"");
for(i=0; i<8; i++) {
printf("Zeichen %x [%c]\n", string[i], string[i]);
}
return 0;
}
|
track@track:~$ ./string_test
Zeichen 61 [a]
Zeichen 62 [b]
Zeichen 63 [c]
Zeichen 64 [d]
Zeichen 65 [e]
Zeichen 66 [f]
Zeichen 67 [g]
Zeichen 0 []
Zeichen 0 [] # <- gleich das 1. Zeichen ist 0x00
Zeichen 62 [b]
Zeichen 63 [c]
Zeichen 64 [d]
Zeichen 65 [e]
Zeichen 66 [f]
Zeichen 67 [g]
Zeichen 0 [] Die 0x00 kannst Du natürlich auch direkt dort hineinschreiben. Aber warum fragst Du das ? - normalerweise wird man einen unbenutzten Speicherbereich einfach so lassen wie er ist. track
|
Progressive
(Themenstarter)
Anmeldungsdatum: 22. Januar 2016
Beiträge: 166
|
Ah, ja, hatte zwar mehr an einen direkten Befehl gedacht aber vom Umfang her nimmt sich das ja nichts 😀 Danke! track schrieb: Aber warum fragst Du das ? - normalerweise wird man einen unbenutzten Speicherbereich einfach so lassen wie er ist.
Ich habe das jetzt so verstanden, dass, wenn ich eine Zeile auslese, in einen String speicher, diesen wegschreibe und dann mit demselben string die nächste Zeile auslese, dass, wenn diese weniger Zeichen enthält, als die vorherige, am Ende des strings dann noch Zeichen aus der vorigen Zeile stehen ? Oder wird der "alte Teil" dann quasi doch nicht berücksichtigt, weil per 0x00 vom restlichen string getrennt ? Sofern man nicht gezielt auf die Adresse zugreift. Suche nun nach der besten Methode, um die einzelnen Werte aus dem String in gesonderte vectoren zu legen.
Ich sehe folgende Möglichkeiten mittels sscanf
string::substr (und mittels strtol/strtof in die vectoren schreiben)
istringstream
strtok() Was ist besser ? Unter Beachtung, dass die Werte um 1-3 Zeichen varrieren könn(t)en.
Via getline die direkt wegzuschreiben geht ja scheinbar nicht, da delim in dem Sinne keine substrings einleitet, sondern das Auslesen des strings abbricht. sscanf birgt wahrscheinlich den geringsten "Aufwand" und händelt auch etwaig unterschiedliche Zahlenlängen ?
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Progressive schrieb: Ich habe das jetzt so verstanden, dass, wenn ich eine Zeile auslese, in einen String speicher, diesen wegschreibe und dann mit demselben string die nächste Zeile auslese, dass, wenn diese weniger Zeichen enthält, als die vorherige, am Ende des strings dann noch Zeichen aus der vorigen Zeile stehen ? Oder wird der "alte Teil" dann quasi doch nicht berücksichtigt, weil per 0x00 vom restlichen string getrennt ? Sofern man nicht gezielt auf die Adresse zugreift.
Genau so. Wenn Du den neuen String als String liest, endet der auf jeden Fall beim ersten 0x00. Trotzdem kannst Du natürlich auf die Bytes dahinter noch zugreifen. (siehe mein Beispiel oben) Suche nun nach der besten Methode, um die einzelnen Werte aus dem String in gesonderte vectoren zu legen. ...
Das ist jetzt wieder eine spezielle C++- Frage - das müssten also die Anderen beantworten. LG, track
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
track schrieb: Progressive schrieb:
Suche nun nach der besten Methode, um die einzelnen Werte aus dem String in gesonderte vectoren zu legen. ...
Das ist jetzt wieder eine spezielle C++- Frage - das müssten also die Anderen beantworten.
Das ist jetzt aber langsam ein neues Thema. Für Textextraktion bieten sich oft reguläre Ausdrücke an. Du müsstest allerdings genauer mitteilen, welche Art Deine Datenverarbeitung sein soll, damit man etwas empfehlen kann.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
track schrieb: Progressive schrieb: Ich habe das jetzt so verstanden, dass, wenn ich eine Zeile auslese, in einen String speicher, diesen wegschreibe und dann mit demselben string die nächste Zeile auslese, dass, wenn diese weniger Zeichen enthält, als die vorherige, am Ende des strings dann noch Zeichen aus der vorigen Zeile stehen ? Oder wird der "alte Teil" dann quasi doch nicht berücksichtigt, weil per 0x00 vom restlichen string getrennt ? Sofern man nicht gezielt auf die Adresse zugreift.
Genau so. Wenn Du den neuen String als String liest, endet der auf jeden Fall beim ersten 0x00. Trotzdem kannst Du natürlich auf die Bytes dahinter noch zugreifen. (siehe mein Beispiel oben)
Aber natürlich nicht verlässlich, denn wie std::string Speicher verwaltet, ist ein Implementierungsdetail. Zugriff auf die einzelnen Zeichen soll nur nach dem Contract von std::string erfolgen. Es ist auch völlig egal, ob die interne Zeichenkette länger ist oder nicht. Entscheidend ist, was std::string::length() (oder size() ) liefert. Es ist nur garantiert, dass auf Indices im Intervall [0, size()[ zugegriffen werden kann. Diese ganzen Erwägungen über die Interna braucht man nur in extremen Sonderfällen - ansonsten lenken die nur von der eigentlichen Aufgabe ab. Der Punkt von OO ist doch gerade, dass man eine öffentliche Schnittstelle zu einem Objekt hat und sich nur um diesen Contract kümmern muss. Alles andere sind Implementierungsdetails der Klasse.
|
Progressive
(Themenstarter)
Anmeldungsdatum: 22. Januar 2016
Beiträge: 166
|
rklm schrieb: track schrieb: Progressive schrieb:
Suche nun nach der besten Methode, um die einzelnen Werte aus dem String in gesonderte vectoren zu legen. ...
Das ist jetzt wieder eine spezielle C++- Frage - das müssten also die Anderen beantworten.
Das ist jetzt aber langsam ein neues Thema. Für Textextraktion bieten sich oft reguläre Ausdrücke an. Du müsstest allerdings genauer mitteilen, welche Art Deine Datenverarbeitung sein soll, damit man etwas empfehlen kann.
Soll ich ein neues Thema öffnen ? Was sind denn reguläre Ausdrücke ?
Die Daten entsprechen Parametern bestimmter Bauteile (nur ein Typ von Bauteil), also letztlich ein Datensatz repräsentiert ein Bauteil. Und mittels diverser Toleranzwerte möchte ich jeweils zwei Bauteile derart zusammenführen, dass ich eine Maximalanzahl generieren kann. Dafür muss ich die Daten in einem Algorhitmus via Matrizzen miteinander verrechen und Minima/Maxima usw. bestimmen.
Zunächst wollte ich erstmal alles drumherum erledigen, bis ich mich mit dem Hauptpart, also dem Algorhitmus, auseinandersetze. Daher quasi das Anliegen, wie man die Daten am sinnigsten "speichert". Für C habe ich das alles mit arrays gemacht. rklm schrieb: track schrieb: Progressive schrieb: Ich habe das jetzt so verstanden, dass, wenn ich eine Zeile auslese, in einen String speicher, diesen wegschreibe und dann mit demselben string die nächste Zeile auslese, dass, wenn diese weniger Zeichen enthält, als die vorherige, am Ende des strings dann noch Zeichen aus der vorigen Zeile stehen ? Oder wird der "alte Teil" dann quasi doch nicht berücksichtigt, weil per 0x00 vom restlichen string getrennt ? Sofern man nicht gezielt auf die Adresse zugreift.
Genau so. Wenn Du den neuen String als String liest, endet der auf jeden Fall beim ersten 0x00. Trotzdem kannst Du natürlich auf die Bytes dahinter noch zugreifen. (siehe mein Beispiel oben)
Aber natürlich nicht verlässlich, denn wie std::string Speicher verwaltet, ist ein Implementierungsdetail. Zugriff auf die einzelnen Zeichen soll nur nach dem Contract von std::string erfolgen. Es ist auch völlig egal, ob die interne Zeichenkette länger ist oder nicht. Entscheidend ist, was std::string::length() (oder size() ) liefert. Es ist nur garantiert, dass auf Indices im Intervall [0, size()[ zugegriffen werden kann. Diese ganzen Erwägungen über die Interna braucht man nur in extremen Sonderfällen - ansonsten lenken die nur von der eigentlichen Aufgabe ab. Der Punkt von OO ist doch gerade, dass man eine öffentliche Schnittstelle zu einem Objekt hat und sich nur um diesen Contract kümmern muss. Alles andere sind Implementierungsdetails der Klasse.
Ah, ok.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17548
Wohnort: Berlin
|
Ich fühle mich jetzt schuldig diese Low-level-Implementierung populär gemacht zu haben:
| if(line.length() > 1 && line[0] == 'f' && line[1] == 'i' && line[2] == 't')
|
aber an einem Zeilenanfang der Länge zwei, an das der Test auf length > 1 noch erinnert. Bei längeren Texten gerät man da rasch an die Grenzen der Eleganz. C++ habe ich schon ein paar Jahre nicht mehr benutzt, außer mal hier und da im Forum einem Anfänger zu helfen. Bestimmt hat die Standardbibliothek von String Methoden, um den Anfang eines Strings zu testen nur kenne ich die nicht und habe kein Handbuch zur Hand. Soetwas wie line.startsWith ("fit") sollte vorhanden sein und auch eine Absicherung für zu kurze Strings haben, und ist dann zu bevorzugen. Vielleicht auch line.matches ("fit.*") - man müsste eben das Handbuch mal lesen. Wahrscheinlich findet man noch sonst sehr viel nützliches.
|
Progressive
(Themenstarter)
Anmeldungsdatum: 22. Januar 2016
Beiträge: 166
|
Sowas wäre smooth ☺ Gibt es nicht online entsprechende Quellen ?
Aber kann mich auch schonmal nach einem Buch umgucken.
|
Progressive
(Themenstarter)
Anmeldungsdatum: 22. Januar 2016
Beiträge: 166
|
Habe std::equal(string.begin(), string.end(), string2.begin()) gefunden ( http://stackoverflow.com/questions/1878001/how-do-i-check-if-a-c-string-starts-with-a-certain-string-and-convert-a-sub ). Allerdings klappt die Implementierung nicht: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | int compare(int start = 378, int ignore_matched_apds = 1, int select_grids = 0, const char *inputfile="Test.txt", const char *apds_glued_file="apds_glued.txt", const char *grids_file="grids.txt", const char *outputfile="apds_matched.txt", const char *simple_outputfile="simple_apds_matched.txt")
{
ifstream database, glued_apds, grids;
ofstream output(outputfile), simple_output(simple_outputfile);
string database_line, glued_apds_line, grids_line;
vector<string> vector_database_lines;
string database_line_begin = "fit data:";
float SN, T, rad, grid, grid_pos, M, Ubias, Id, dM;
int max = 0;
vector<string>::iterator it;
database.open(inputfile);
if(!database) cerr << "File \"" << inputfile << "\" not found\n" << endl;
else
{
cout << "Open file \"" << inputfile << "\" as database" << endl;
while(getline(database,database_line))
{
if(equal(database_line.begin(), database_line.end(), database_line_begin.begin()))
{
getline(database,database_line);
getline(database,database_line);
vector_database_lines.push_back(database_line);
cout << database_line << endl;
}
}
if(vector_database_lines.size()==0)
{
cout << "Reading from \"" << inputfile << "\" failed" << endl;
return (-1);
}
else max = vector_database_lines.size();
}
}
|
Das Auslesen klappt nicht wirklich. Die Bedingung ist öfter erfüllt, als sie dürfte.
Wenn ich einen beliebigen string definiere, klappt es. Aber von der Datei kommend irgendwie nicht.
- Test.txt (1.3 KiB)
- Download Test.txt
|
xentoor
Anmeldungsdatum: 27. September 2016
Beiträge: 8
|
Hallöchen, ich hab mir mal den Spaß gemacht den Code aus deinem Letzten Beitrag nachzubauen. Hier das Ergebnis: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 | #include <iostream>
#include <fstream>
#include <string>
#include <vector>
int doStuff(std::string inputfile, std::string outputfile)
{
std::ifstream ifile(inputfile, std::ifstream::in);
if(!ifile.is_open())
{
std::cerr << "Could not open " << inputfile << std::endl;
return -1;
}
std::cout << "Opened " << inputfile << " for input." << std::endl;
std::ofstream ofile(outputfile, std::ifstream::out);
if(!ofile.is_open())
{
std::cerr << "Could not open " << outputfile << std::endl;
return -1;
}
std::cout << "Opened " << outputfile << " for output." << std::endl;
std::string line;
std::vector<std::string> vector_lines;
std::string match_string = "fit data:";
std::vector<float> numbers;
while(!ifile.eof())
{
getline(ifile,line);
if(line.compare(0,match_string.length(),match_string) == 0)
{
getline(ifile,line);
getline(ifile,line);
vector_lines.push_back(line);
std::cout << line << std::endl;
std::size_t next = 0;
while(line.length() > 0)
{
numbers.push_back(std::stof(line,&next));
line = line.substr(next);
}
}
}
int max = 0;
if(vector_lines.empty())
{
std::cerr << "Reading from " << inputfile << " failed. " << std::endl;
return -1;
}
else max = vector_lines.size();
for(int i = 0; i < max; ++i)
ofile << vector_lines.at(i) << std::endl;
std::cout << max << " lines saved to " << outputfile << "." << std::endl;
for(int i = 0; i < numbers.size(); ++i)
std::cout << numbers.at(i) << std::endl;
ofile.close();
ifile.close();
return 0;
}
int main (int argc, char* argv[])
{
if(doStuff("testinput","testoutput") == 0)
std::cout << "Erfolg" << std::endl;
else
std::cout << "Fehler" << std::endl;
return 0;
}
|
Wenn ich das auf dein Text.txt loslasse bekomme ich folgenden output:
Opened testinput for input.
Opened testoutput for output.
0912009913 -25.1 0 215 10 150 360.26770007 -0.157245 5.997866
0912009897 -25.1 0 215 9 150 353.638682453 -0.14171 6.102571
2 lines saved to testoutput.
9.1201e+08
-25.1
0
215
10
150
360.268
-0.157245
5.99787
9.1201e+08
-25.1
0
215
9
150
353.639
-0.14171
6.10257
Erfolg Das Vergleichen auf deinen String 'fit data:' ist mit der compare Methode der String Klasse ganz einfach. Hier siehst du was die String Klasse an weiteren Methoden hat (http://www.cplusplus.com/reference/string/string/).
Wie user_unknown schon angemerkt hat sind die Methoden der Klasse String durchaus abgesichert gegen zu kurze Strings. Auch ist der Zugriff auf einzelne Zeichen über die .at() Methode mMn dem Zugriff über [i] vorzuziehen, da bei out-of-range access ne exception geworfen wird, die man dann behandeln könnte.
Ich hab mir auch mal den Spaß gemacht die String bestandteile in nen Vector<float> zu verpacken und auszugeben. Vielleicht hilft dir das ja nochmal weiter.
Wieso übergibst du eigtl. die Dateinamen nicht als String, hat das einen Grund?
|