![]() |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
dann betone ich hiermit was für was geeignet ist (abgesehen vom StringReplace, das fliegt generell raus) Für Strings die Text enthalten wie "Ich bin ein String der Text enthält." kann man alle methoden nehmen. Für Strings die binär sind: CountCharInString(), CharInStringA() und CharCount() nicht verwenden. |
AW: Anzahl eines Zeichens im String ermitteln
Ich werfe noch eine Version in die Runde, die auch auf den mobilen Plattformen funktioniert (Stringzählung beginnt bei Null):
Delphi-Quellcode:
Auch ein #0 dazwischen stört nicht. Alternativ kann man noch mit Low (s) to High (s) arbeiten (so bei mir i.d.R. für Cross Plattform Projekte in der Anwendung).
function StringCountChar(const S: string; const C: Char): Integer;
var ch: Char; begin Result := 0; for ch in S do begin if ch = C then Inc(Result); end; end; Auch wenn Du derzeit mit D2009 ide mobilen Plattformen noch nicht bedienen kannst, könnte es ja nicht schaden, seine Funktionen auf denkbare Eventualitäten zu rüsten. Solche Sachen später zu finden und zu beheben ist nämlich nicht ganz ohne Mühe... EDit: Sehe gerade in Beitrag #14 kam das schon mal... Na ja, dann eben zur Erinnerung... |
AW: Anzahl eines Zeichens im String ermitteln
Wenn es wirklich auf die Performance ankommt, blieben noch spezielle CPU Instruktionen wie repne scasb bzw. repne scasw. Die habe ich auch schon benutzt, aber das macht nur Sinn, wenn es wirklich Not tut. Eben wegen Portabilität usw.
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Ich würde mich über eine besser funktionierende Version als diese hier freuen, mein assembler ist doch stark eingerostet. Vielleicht ist Code auch korrekt nur Ausführung ist recht langsam weil ich ein PChar rauswerfe wo man mit Length() die Treffer abfragt.
Delphi-Quellcode:
function StrScanAsm(Str: String; Chr: Char): PChar; assembler;
asm OR EAX,EAX JZ @@2 PUSH EDI MOV ECX,[EAX-4] MOV EDI,EAX MOV EAX,EDX REPNE SCASB MOV EAX,0 JNE @@1 MOV EAX,EDI DEC EAX @@1: POP EDI @@2: end; |
AW: Anzahl eines Zeichens im String ermitteln
Nur so zum Spaß noch eine Version, die auch mit PChar arbeitet, aber trotzdem #0 Zeichen im String zulässt.
(Kann sein, daß die Pointer-Arithmetik in älteren Versionen noch nicht funktioniert. Dann die auskommentierte Variante verwenden.)
Delphi-Quellcode:
function CharCount(const S: string; C: Char): Cardinal;
var P, PEnd: PChar; begin Result := 0; P := PChar(S); PEnd := P + Length(S)); // PEnd := P; // Inc(PEnd, Length(S)); while P < PEnd do begin while P^ <> C do begin Inc(P); if P = PEnd then Exit; end; Inc(Result); Inc(P); end; end; |
AW: Anzahl eines Zeichens im String ermitteln
Müßte es nicht heißen
Delphi-Quellcode:
?
inc(p^,sizeof(char));
Gruß K-H |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Das
Delphi-Quellcode:
ist hier nicht nur nicht notwendig, sonder wäre sogar schädlich. Bei typisierten Pointern (hier PChar) wird bei Inc/Dec die Größe des Typs (in diesem Fall Char) berücksichtigt. Funktioniert auch hervorragend mit Pointern auf Records. Lediglich bei (untypisiertem) Pointer wird byte-weise verändert.
Sizeof(Char)
![]() Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Danke Uwe, funktioniert Pfeilschnell auch im binär Modus. Das ist mein momentaner Favorit, das alte StrScan() verschwindet somit.
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Wegen Portabilität und so: Ihr berücksichtigt keine Unicode Surrogate-Paare.
Und zu den Assembler Varianten: geht das auch auf 64-Bit? Und wem die primitiv-Variane zu langsam ist sollte erst mal prüfen warum man die Suche überhaupt braucht. Die zu vermeiden ist meist der wesentlich schnellere Weg. In der Regel ist der aufrufende Code sch...licht verbesserungswürdig. |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Zitat:
Surrogate selber kann man aber nicht suchen, bzw. eben nur einzeln nach den beiden Hälften. |
AW: Anzahl eines Zeichens im String ermitteln
@Uwe
Schaut gut aus! No a bizzl kürzer:
Delphi-Quellcode:
function CharCount(const S: string; C: Char): Cardinal;
var P, PEnd: PChar; begin Result := 0; P := Pointer(S); if P = nil then Exit; PEnd := P + PLongInt(NativeUInt(P) - SizeOf(LongInt))^; while P < PEnd do begin Inc(Result, Ord(P^ = C)); Inc(P); end; end; |
AW: Anzahl eines Zeichens im String ermitteln
Ein gutes Beispiel für Codes, die in 64 Bit gnadenlos abrauchen.
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Edit:
Code:
function CharCount(const S: string; C: Char): Cardinal;
var P, PEnd: PChar; begin Result := 0; P := Pointer(S); if P = nil then Exit; {$IFNDEF FPC} PEnd := P + PLongInt(NativeUInt(P) - SizeOf(LongInt))^; {$ELSE} PEnd := P + PSizeInt(NativeUInt(P) - SizeOf(SizeInt))^; {$ENDIF} while P < PEnd do begin Inc(Result, Ord(P^ = C)); Inc(P); end; end; |
AW: Anzahl eines Zeichens im String ermitteln
Ich poste meine Assembler Version einfach mal.
Delphi-Quellcode:
Damit erreiche ich momentan den 2. Platz im Benchmark (CountCharInString gewinnt).
function CharCountAsm(AStr: PChar { eax }; AChar: Char { dx }; len: Integer { ecx }): Integer;
label loop_start, loop_ende, ende; asm // Danke gammatester! - sorgt dafür dass scasw vorwärts und nicht rückwärts sucht cld // edi + ax für scasw initialisieren mov edi, eax mov ax, dx // edx = char count := 0 xor edx, edx loop_start: repnz scasw // bis zum nächsten Vorkommen "vorspulen" jcxz loop_ende // Wenn String zu Ende, aus Schleife springen inc edx // Vorkommen des Chars mitzählen jmp loop_start loop_ende: jnz ende inc edx // Falls der letzte Buchstabe noch ein Treffer war ende: mov result, edx end; i := CharCountAsm(@Data[1], 'X', Length(Data)); ACHTUNG: Da scheint auch noch irgendwo ein kleiner Denkfehler drin zu sein :!: In (relativ) seltenen Fällen zählt mein Code aus irgendeinem Grund falsch. Falls jemand eine Idee hat wo der Fehler ist oder wie man den Code generell noch verbessern/verschnellern kann wäre das super! 64-Bit ginge natürlich auch, aber habe wenig Erfahrung mit 64 Bit Assembler, deswegen lasse ichs erst mal. |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Delphi-Quellcode:
ist da auch nicht viel schlechter (ca. 50% länger als mein letzter Ansatz und ca. 20% länger als dein Vorschlag).
S.CountChar(C)
Offenbar sind die Ansätze mit PChar und Inc(P) potentiell schneller als indizierte Zugriffe in For-Schleifen. Ob der erreichbare Geschwindigkeitsgewinn aber die schlechtere Lesbarkeit und Wartbarkeit (siehe die ganzen Probleme mit Assembler) rechtfertigt, ist wohl eher zweifelhaft. Ich habe den Benchmark etwas modifiziert und rufe die einzelnen Probanden 10000x auf um lokale Schwankungen auszugleichen - natürlich außerhalb der IDE und im Release-Mode. Messungen im Nanosekundenbereich sind einfach nicht verlässlich genug. Da der String per Zufall generiert wird, kann man verschiedene Läufe auch nicht direkt miteinander vergleichen, nur die Rangfolge innerhalb eines Laufs. Der Zeichensatz ist ja auch etwas eingeschränkt gewählt. |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Man kann ja auch die RandomString() seperat aufrufen um damit eine feste Datei erzeugen.
Ich wollte den Traffic sparen und fand hier in DP diese nützliche Unit um Strings beliebiger Länge zu generieren in dem moment praktikabler aber der Replikation und Schwankungen zur Folge hast Du Recht, so ist es nur eine objektive Momentaufnahme. Bei Tokyo ist ja TStopWatch enthalten, die Timing-Funktion kann man damit auch ersetzen/erweitern, ob damit andere/bessere Ergebnisse rauskommen? |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
String[i] ist immer langsam. Die Schleife ist da nicht unbedingt schuld, sondern die permanente Indexierung der Speicheraddresse und die damit verbundenen RangeChecks. Durch deinen CodeStyle ak. Pointer-Math gibt es eben diese Checks erst gar nicht nicht.
Delphi-Quellcode:
@Himitsu,
function CharCount(const S: string; C: Char): Cardinal;
var P, PEnd: PChar; begin Result := 0; P := Pointer(S); if P = nil then Exit; {$IFNDEF FPC} PEnd := P + PLongInt(NativeUInt(P) - SizeOf(LongInt))^; {$ELSE} PEnd := P + PSizeInt(NativeUInt(P) - SizeOf(SizeInt))^; {$ENDIF} while P < PEnd do begin if P^ = C then Inc(Result); Inc(P); end; end; was soll da nicht stimmen? Das TStrRec ist sowol unter Delphi64/32 bit gleich definiert. Also wo ist der Haken, wenn du es schon ansprichst? |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Dann ändert Emba die Struktur und es knallt. :stupid: Wenn möglich also immer vordefinierte Casts/Funktion nutzen und nicht gefährlich selber auf interne Strukturen zugreifen. Ich sehe hier auch keinen Vorteil, weswegen nicht Length verwendet werden kann. Die Funktion hat dann sogar 70% weniger Code. Und auch für die anderen Informationen gibt es schon seit 9 Jahren fertige Funktionen.
Delphi-Quellcode:
Gut, bissl blöd ist, dass
{ string info utilities }
function StringElementSize(const S: UnicodeString): Word; overload; inline; function StringElementSize(const S: RawByteString): Word; overload; inline; function StringCodePage(const S: UnicodeString): Word; overload; inline; function StringCodePage(const S: RawByteString): Word; overload; inline; function StringRefCount(const S: UnicodeString): Integer; overload; inline; function StringRefCount(const S: RawByteString): Integer; overload; inline; {$IFNDEF MSWINDOWS} function StringElementSize(const S: WideString): Word; overload; inline; function StringCodePage(const S: WideString): Word; overload; inline; function StringRefCount(const S: WideString): Integer; overload; inline; {$ENDIF}
Delphi-Quellcode:
in der System-Unit nicht öffentlich deklariert sind, sonst könnte man sie direkt zum Casten nehmen.
type
PStrRec = ^StrRec; StrRec = packed record codePage: Word; elemSize: Word; refCnt: Longint; length: Longint; end; PDynArrayRec = ^TDynArrayRec; TDynArrayRec = packed record RefCnt: LongInt; Length: LongInt; end; |
AW: Anzahl eines Zeichens im String ermitteln
Assoooo! Und ich dachte schon ...
Der code ist mir klar. Auch die möglicherweise begleitenden Probleme die sich durch den Anruf bei Emba ergeben könnten. Wenn man so mit dem Speicher spielt, sollte das auch klar sein. Da greift man auch anders an:
Delphi-Quellcode:
Das gewöhnt man sich an, wenn gleicher code von D2...XE10.2 laufen soll, jedoch inline code erst seit D2005 möglich ist und jeder call 50cycles verschwended, wie mir Uwe so schön gezeigt hat.
type
//zentral deklariert PStrLenInt ^StrLenInt; StrLenInt = {$IFDEF FPC}SizeInt{$ELSE}LongInt{$ENDIF}; // sollte Delphi den speicher bereich über 2/4GB wie FPC-64 jemals erweitern, würde da ein weiteres Property-Based define den richtigen Type declarieren. // somit schaut der code so aus: function CharCount(const S: string; C: Char): Cardinal; var P, PEnd: PChar; begin Result := 0; P := Pointer(S); if P = nil then Exit; PEnd := P + PStrLenInt(NativeUInt(P) - SizeOf(StrLenInt))^; while P < PEnd do begin if P^ = C then Inc(Result); Inc(P); end; end; Bedenken hin oder her, wo jedoch ist das CPU64 Problem? Oder gibt es doch keins? Edit PS.: 4GB sind yuch nur für den UnicodeString verfügbar, da ElementSize = 2 ist, theoretische 8GB für einen UCS4String (wenn es den gibt unter Delphi?) und nur 2GB für all SingleByte-Long-Strings. Edit2: Selbst wenn StrRec/PStrRec definiert wären wie soll denn dann der Cast ausschauen? Du hast nur einen Speichblock mit n-Bytes. Eine cast über PStrRec müßte auch rückwärts (SizeOf(StrRec))gerechnet werden. |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Aber das war nicht das Problem. Dann hätte ich mich wahrscheinlich nicht verzählt sondern direkt ne Zugriffsverletzung erhalten. |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Klappt es denn mit cld als erste Anweisung bei dir? |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Delphi-Quellcode:
function TTextReaderHelper.ReadQuotedLine(QuoteChar: Char): string;
var line: string; begin Result := ReadLine; if Odd(Result.CountChar(QuoteChar)) then begin { Eine ungerade Anzahl von Quotes bedeutet, daß der gequotete String mindestens einen Zeilenumbruch enthält. Wir hängen also die nachfolgenden Zeilen mit LineBreak an, bis eine weitere Zeile mit ungerader Anzahl Quotes kommt. } repeat Result := Result + sLineBreak; line := ReadLine; Result := Result + line; until Odd(line.CountChar(QuoteChar)); end; end; |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Übrigens: Bei den Funktionen, die auch #0 Zeichen im String zulassen und somit auch danach suchen lassen, muss man beachten, daß der String immer mit einem #0 Zeichen abgeschlossen wird (bei Length + 1), aber dieses nicht mitgezählt werden darf. |
AW: Anzahl eines Zeichens im String ermitteln
Liste der Anhänge anzeigen (Anzahl: 1)
Neutral General, Danke für Deinen Post, bei mir leider auch gleich eine EA.
Falls wer mag, habe den Benchmark etwas umgestaltet. Nun führt der zwei Tests durch, einmal mit RandomString() und einmal mit RandomByte(). Sprich, einmal sind es nur lesbare ASCII Zeichen beim zweiten Test ist ein 00-FF Byte möglich. Um lokale Schwankungen zu minimieren bzw. in dieser Test-Art besser Auszugleichen habe ich einfach den Daten Anteil auf 50MB erhöht. Danke EgonHugeist, Deine Variante ist auch enthalten. Im Anhang Projekt-Source plus Kompilat zum gleich Testen. |
AW: Anzahl eines Zeichens im String ermitteln
Das verstehe ich nicht. Kannst du mal bitte zeigen wie du meine Funktion aufgerufen hast?
Bei mir läuft alles ohne Probleme (Sowohl mit Release als auch Debug Konfiguration, 32-Bit, Windows 10) |
AW: Anzahl eines Zeichens im String ermitteln
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habs so wie Du geschrieben hast verwendet. Siehe hier: Anhang 49502
|
AW: Anzahl eines Zeichens im String ermitteln
Ist das die Version mit oder ohne cld?
Welche Windows/Delphi Version,welche Konfiguration? Würde echt gerne wissen wo es da kracht. Ich sehe da eigentlich keine problematische Stelle. |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Mit abgeschalteter Optimierung brauchen die Pascal-Funktionen aber deutlich länger. Wobei sich dann wieder die Verwendung der internen Funktionen (StrScan oder string.CountChar) bezahlt macht, da die von dem Schalter nicht betroffen sind. |
AW: Anzahl eines Zeichens im String ermitteln
Ach ja, statt Randomize verwende ich
Delphi-Quellcode:
RandSeed := 0;
|
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
![]() Zitat:
Zitat:
Zitat:
|
AW: Anzahl eines Zeichens im String ermitteln
Ich habe so ein bisschen das Gefühl, dass bei euch (aus welchem Grund auch immer) die Parameter nicht in den Registern ankommen wie es sein sollte/normalerweise ist.
Funktioniert diese Version bei euch?
Delphi-Quellcode:
function CharCountAsm(AStr: PChar; AChar: Char; len: Integer): Integer;
label loop_start, loop_ende, ende; asm cld // Explizite Zuweisung der Parameter in die Register mov edi, AStr mov ax, AChar mov ecx, len xor edx, edx loop_start: repnz scasw jcxz loop_ende inc edx jmp loop_start loop_ende: jnz ende inc edx ende: mov result, edx end; |
AW: Anzahl eines Zeichens im String ermitteln
Zitat:
Ich sollte meine Pointer-Kenntnisse einmal auffrischen. Gruß K-H |
AW: Anzahl eines Zeichens im String ermitteln
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
An dieser Stelle kracht es. edit Also irgendwie stimmt was mit "Len" und übergabe nicht bei mir. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:54 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz