in AnsiString nach \n\r suchen um Zeilenanzahl zu ermitteln
-
Peter schrieb:
Okay okay, Pointer in AnsiStrings ist manch einem ein Dorn im Auge, aber wir proggen schließlich in C/C++, greifen hier ja nur lesend zu [...]
Macht unter Umständen absolut keinen Unterschied, da der Inhalt genau gleich zerstört werden könnte. Dazu muss man allerdings entweder Multi-Threaded Programmieren oder mitten drin Application->ProcessMessages() aufrufen, was einem Pseudo-Multithreading ähnlich kommt.
-junix
-
Hallo junix ***freuhüpfundheftigwink***
-
Könnt ihr bitte das Problem auch für mich(jemanden der noch nich soviel mit BCB gecodet hat) verständlich erklären?
Danke
-
Grüss dir, Peter. Hast aj eh nur auf meinen Kommentar gewartet (o; - Ich warte immernoch bis dein Name auftaucht bei den Forentreffenanmeldungen (o;
@ela: Das ist ein generelles problem mit Zeigern auf einen klasseninternen Puffer und hat nix mit dem BCB zu tun:
Stell dir vor du schreibst einen String in die AnsiString Klasse. Diese reserviert einen char-puffer im Speicher und speichert den String ab. Nun holst du dir den zeiger auf diesen Puffer mittels c_str().
Während du nun in diesem Puffer wuselst, schreibt aber ein anderer nen neuen String in dieses AnsiString Objekt oder mutiert den String.
Nun kann es passieren, dass das AnsiString Objekt den kompletten Puffer freigibt und irgendwo nen neuen Puffer reserviert, während du mit dem alten Zeiger weiter wuselst.Der Punkt ist nun der, dass du in einem ungültigen Speicherbereich rumliest (und ev. auch schreibst). -> Segmentation faults oder mind. falsche Resultate sind vorprogrammiert.
Dies passiert allerdings nur bei (quasi) Nebenläufigkeiten wie sie in MultiThreaded-Applikationen oder eben mit TApplication::ProcessMessages() auftreten können.
Man spricht in diesem Zusammenhang auch oft von "nicht Threadsicher".In deinem Speziellen Fall allerdings, wo es sich beim AnsiString um ein lokales Objekt handelt, ist es absolut ungefährlich. Denn in diesem lokalen Objekt kann ja niemand ausser deine eigene Funktion rum pfuschen.
... ich glaub ich schreib das mal etwas ausführlicher in die FAQ...
Ich hoffe ich habe mich verständlich ausgedrückt, ansonsten: Nachfragen.
-junix
[edit="junix"]Vielleicht noch ergänzend: Der Punkt, wieso ich immer wieder mit dem Ganzen hinterm Berg hervorkomme ist der, dass diese Problematik hässliche, kaum reproduzierbare Fehler verursachen kann. Schlussendlich ist es natürlich Ermessenssache, ob man sowas wies Peter vorgeschlagen hat verwenden will oder nicht. (Wie es bei vielen anderen gepredigten Regeln wie z.B. globalen Variablen, goto, etc. auch der Fall ist)
Ich behaupte allerdings ganz kühn (und Peter wird mir da vermutlich zustimmen), dass die Minderheit hier im Forum wirklich die Tragweite der Verletzungen solcher Regeln sieht. Daher heisst hier auch immer die Devise, dass die Ratschläge und Tips sich auf der sicheren Seite bewegen sollten. Ansonsten ist niemandem geholfen.
Da ich die wenigsten hier "kenne und einschätzen" kann, bete ich immer wieder diese Regeln und Probleme runter.[/edit]
-
Danke junix, ich hab verstanden was du meinst.
@Peter
der Code funzt sehr gut und da ich nicht nur nach dem "\r\n" suchen muss, sondern dann auch noch nach der Anzahl der Tabs die bis zu einem bestimmten Eintrag stehen werd ich mir gleich Deinen Code etwas abändern.Danke nochmal.
Ich hab das gerade versucht dann noch so umzubauen, das die "\t" die vorhanden sind gezählt werden, aber die for-schleife nur solang laufen soll bis in dem String ein bestimmtes Wort steht z.B. Name, aber das geht noch irgendwie schief.
Könnt ihr mir da bitte noch einen Tip geben?
-
Hi, ich nochmal,
ich hab folgendes Problem:
den Code vom Peter hab ich bei mir eingefügt, allerdings den Zweiten Til nicht in eine Funktion ausgelagert.
Ich will nun die gleiche Funktion ein paar Zeilen später nochmal verwenden:... comp =*((short*)"\t"); for(p=Zeile[0].c_str(); *p!=0; p++) { if(*((short*)p)==comp) anzTab++; }
aber da funktioniert es nicht, WARUM
Ich hab es schon versucht indem ich mir alle Variablen nochmal angelegt habe (natürlich andere Namen) aber auch da funt es nichtUnd noch etwas, wie bekomme ich es am besten hin das er für die Stelle
*p!=0
das aufgehört wird, wenn die Position von p auf den Eintrag "Namen" zeigt ?
Also mal zum Beispiel:
in Zeile[0] steht: "Test\tTyp\tName\tOperand\r\n"
als Ergebnis muüsste ich jetzt für anzTab 2 rausbekommen.
Aber das haut nicht hin.Ich bitte um HILFE
-
Wenn Du nur einen Character suchst (char) und nicht Zwei (short int), brauchst Du natürlich nicht mit (short*) zu casten. Alles weitere später, hab grad keine Zeit ...
-
ela schrieb:
den Code vom Peter hab ich bei mir eingefügt, allerdings den Zweiten Til nicht in eine Funktion ausgelagert.
Wieso nicht? Ist doch optimal für eine Funktion....
Ansonsten äh, ja, _WAS_ funktioniert denn nicht? Was passiert beim durchsteppen?
Was deine zweite Frage anbelangt.. das wirst du doch jetzt hoffentlich selbst hinkriegen oder? strcmp kennst du?
-junix
-
@ junix:
ich habs nicht ausgelagert, weil ich es erstmal testen will und schauen muss, wie ich das gesamte am besten hinbekomme, lauft es und ich kann die Funktion nutzen und vielleicht noch etwas abändern, dann wirds ausgelagert.
Okay, also strcmp kenn ich. Da kann man zwei Strings miteinander vergleichen, du meinst also, ich solle test mit "Name" vergleichen? Und dann? In Test steht immer mehr drin wie nur "Name" ??? Ich weiß nicht auf was du hinaus willst, ich glaub ich hab nen Brett vorm Kopf.
-
ela schrieb:
ich habs nicht ausgelagert, weil ich es erstmal testen will und schauen muss, wie ich das gesamte am besten hinbekomme, lauft es und ich kann die Funktion nutzen und vielleicht noch etwas abändern, dann wirds ausgelagert.
Was spricht dagegen, einfach die Funktion zu verwenden? Wieso erst den Code in das Listing eingliedern und dann wieder in eine Funktion ausgliedern? Peters Code ist eigentlich eine typische - eigenständige Funktion, wieso nicht einfach so belassen? Ich rieche Spaghetti-Code...
ela schrieb:
Okay, also strcmp kenn ich. Da kann man zwei Strings miteinander vergleichen, du meinst also, ich solle test mit "Name" vergleichen? Und dann? In Test steht immer mehr drin wie nur "Name" ??? Ich weiß nicht auf was du hinaus willst, ich glaub ich hab nen Brett vorm Kopf.
Du weisst doch, wie lang der String ist den du suchst? Also einen Teilstring extrahieren, vergleichen, gut is... Ausser Peter hat mal wieder ne schnellere Lösung...
-junix
-
Hab zwischendurch mal schnell was zusammengeschustert:
void __fastcall TForm1::Button2Click(TObject *Sender) { int linecount; AnsiString str; str="Zeile1\tZeile2\tEla\nZeile3\tZeile4\t"; linecount=CountTabs(str.c_str(), "Ela"); ShowMessage(linecount); } //--------------------------------------------------------------------------- int TForm1::CountTabs(char *str, char *termstr) { register int lents=strlen(termstr); register char *p; register int tabs=0; for(p=str; *p!=0; p++) { if(!strncmp(p, termstr, lents)) break; if(*p=='\t') tabs++; } return tabs; }
@junix
Über das Thema AnsiString und Pointer hatten wir uns ja auch schon mal früher unterhalten, gell
In Punkto Forentreff, wenn es in der Stuttgarter Gegend stattfinden sollte und Du auch dabei bist wäre die Möglichkeit groß, daß ich da auch hinkomme. AndreasW habe ich inzwischen schon kennengelernt, allerdings nicht auf einem Forentreff sondern der Roadshow zum BuilderX
-
Stimmt... strncmp hiess das Ding... ich wusste doch da gabs was (o:
@Peter: Ne das ist auf Höhe Frankfurt (o: Aber ich fahr eh in Stuttgart vorbei, da könnte ich dich mitnehmen (o;
-junix
-
Auch auf die Gefahr hin, mich hier sehr beliebt zu machen, will ich Euch
meinen Vorschlag nicht vorenthalten.
Als Freund der TStringList würde ich das ganze so lösen:TStringList* slTemp = new TStringList(); slTemp->Text = help; int anzZeilen = slTemp->Count;
Ob das allerdings auch funktioniert, wenn nur "\n" anstatt "\r\n" verwendet
wird, weiß ich nicht. Leerzeilen werden natürlich auch mitgezählt.Nur mal so als Anregung.
Gruß,
Alexander
-
Abgesehen vom Problem, dass ja offensichtlich \t und nciht \r\n der Delimiter ist, hat die Idee natürlich auch was für sich... man könnte auch TStringList::CommaText verwenden (o: Aber wenn du nur Zeilen zählen willst, dann finde ich die StringList etwas äh Overkill...
-junix
-
junix schrieb:
Abgesehen vom Problem, dass ja offensichtlich \t und nciht \r\n der Delimiter ist
Wieso offensichtlich? Wenn ich mir mal die Überschrift dieses Threads anschaue
(und dabei den Dreher "\n\r" ignoriere) und einen Ausschnitt aus einem Posting
von ela:ela schrieb:
Ich habs im Moment so:
... if(help.Pos("\r\n") != 0) //help beinhaltet den Clipboardinhalt
Da könnte bei mir schon der Eindruck entstehen, als ob "\r\n" gesucht werden
soll.junix schrieb:
Aber wenn du nur Zeilen zählen willst, dann finde ich die StringList etwas äh Overkill...
Deshalb ja auch meine kleines "Vorwort". Dennoch spricht schon was dafür, vor-
gefertigte und (offensichtlich) bewährte Funktionen zu verwenden. Sicherlich
gibt's da effizienteres als die Verwendung einer TStringList. Der Dreizeiler
ist wesentlich überschaubarer und damit weniger fehleranfällig als eine selbst-
geschriebene Routine mit for-Schleife (auch wenn die nicht wirklich kompliziert
ist). Und falls man vielleicht die einzelnen Zeilen noch irgendwie weiterver-
arbeiten will, bietet sich eine Stringliste vielleicht ohnehin an?Gruß,
Alexander
-
OK, offensichtlich war vielleicht der falsche Ausdruck (o: Im Laufe des Threads stellte sich dies aber heraus.
Was das Weiterverarbeiten betrifft: Sicherlich hast du recht. War an dieser Stelle allerdings nicht gefragt. Naja egal. Beide Lösungen haben ihre Vor- und Nachteile. Der grösste Nachteil an der StringList ist das leider etwas langsame ObjectPascal das hinter den Algorithmen steht.
-junix
-
Jou, man könnte hergehen, mit StringReplace alle '\t' durch Komma ersetzen und per CommaText in die TStringList lutschen. Dann Zeile für Zeile durchzählen bis zu dem begrenzenden Textteil ... oder so ähnlich. Wäre auch eine Möglichkeit
-
Peter schrieb:
Jou, man könnte hergehen, mit StringReplace alle '\t' durch Komma ersetzen [...]
Naja, es gibt ja auch noch DelimitedText. Damit läßt sich das etwas eleganter
lösen.Gruß,
Alexander
-
Guten Morgen,
vielen Dank für eure Hilfe, ich werd den Code vom Peter nachher gleich mal testen.
Um nochmal deutlich zu sagen und alle Zweifel zu zerstören, die Thread Überschrift stimmt, das war das was ich gesucht habe, da ich aber die Funktion vom Peter gut finde, und ich nicht nur die Zeilen die im Clipboard stehen brauche, sondern dann auch die Anzahl der Tabs hab ich den Thread auf dieses Problem ausgeweitet.Also nochmal vielen Danke