Leaderboard
Popular Content
Showing content with the highest reputation on 03/21/21 in all areas
-
Somebody had to do it: [RSP-33448] Memory leaks when using styles - Embarcadero Technologies Feel free to add to the report.
-
Multiple string replace - avoid calling StringReplace multiple times
David Heffernan replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I guess if there are no firm rules on the expected behaviour, then that makes it easier to write faster code. -
Multiple string replace - avoid calling StringReplace multiple times
A.M. Hoornweg replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
What I mean is, if you call Embarcadero's stringReplace routine multiple times, then each subsequent replace sees the insertions made by the previous call. But if you write a MultiStringReplace routine that first analyzes the string and determines everything that is to be replaced, that is not the case. It sees only the original string and not the intermediate insertions. The end result may be different. -
ANN: Deleaker 2020.16 with full RAD Studio 10.4 Sydney support
Artem Razin posted a topic in Delphi Third-Party
We are excited to announce to the community that the new Deleaker 2020.16 with full RAD Studio 10.4 Sydney is available to download. Deleaker is a famous tool to find leaks, leaked objects and memory, GDI resources, and handles. This is a good addition to a favorite IDE for everyone who wants to explore resource usage and fix leaks without leaving RAD Studio. For those who prefer to watch, we've recorded a video to show how it works: Happy coding! -
Multiple string replace - avoid calling StringReplace multiple times
David Heffernan replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Do you have a specification about what you want the function to do? It seems like you don't mind. -
I have been working on that. I needed to make a substantial change to using an OpenGL surface - a problem I am having is doing a transform when the device is not oriented in the "normal" position. That already is "tapped", however the SurfaceTextureListener is not the right place. As per my comment above, I've switched to using GLSurfaceView: https://developer.android.com/reference/android/opengl/GLSurfaceView Which uses: https://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer The GLSurfaceView calls onDrawFrame of the Renderer when a new frame is available, so the capture/filtering can be done there. This part is all done in Java, however the Delphi code could "hook" into the filtering, and can already pass a Java bitmap of the resulting frame to Delphi. Again as per above, I want to resolve the transform issue which is currently eluding me. I'm willing to share the work in progress with others if they think they can help. Best to join my Slack workspace to do so: https://slack.delphiworlds.com
-
Multiple string replace - avoid calling StringReplace multiple times
A.M. Hoornweg replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I am a bit puzzled here. How do you want to guarantee a consistent outcome? The first "search & replace" will change the string. It will remove characters and insert new ones. Which may get captured by the next search. Suppose you have a string like "Jabba the Hutt lived in a Hut" and you want to replace "Hutt" by "Alien" and "Hut" by "House". How do you decide which replacement to do first? -
Multiple string replace - avoid calling StringReplace multiple times
balabuev replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Here is my small idea. Not perfect, has limitations, I guess, but usable {$POINTERMATH ON} const GUESS_MASK = 32 - 1; procedure BuildGuess(AGuess: PByte; const aOld: array of string); var pi, j: Integer; begin FillChar(AGuess^, GUESS_MASK + 1, 0); for pi := 0 to High(aOld) do begin j := Ord(aOld[pi][1]) and GUESS_MASK; if AGuess[j] = 0 then AGuess[j] := pi + 1 else AGuess[j] := 255; end; end; function Equals(S1, S2: PChar; ACount: Integer): Boolean; var i: Integer; begin for i := 0 to ACount - 1 do begin if S1[i] <> S2[i] then Exit(False); end; Result := True; end; function MyReplace(const S: string; const aOld, aNew: array of string): string; label L; var lnt: Integer; pcnt: Integer; c, eof: PChar; p: PChar; pi, j: Integer; pln: Integer; off: Integer; guess: array[0..GUESS_MASK] of Byte; begin pln := 0; lnt := Length(S); pcnt := Length(AOld); BuildGuess(@guess, aOld); SetLength(Result, lnt * 2); c := Pointer(S); eof := c + lnt; off := PChar(Pointer(Result)) - c; while c <> eof do begin pi := guess[Ord(c^) and GUESS_MASK]; if pi <> 0 then begin if pi <> 255 then begin Dec(pi); pln := aOld[pi].Length; if (c^ = aOld[pi][1]) and Equals(c, Pointer(aOld[pi]), pln) then goto L; end else begin pi := 0; while pi <> pcnt do begin pln := aOld[pi].Length; if (c^ = aOld[pi][1]) and Equals(c, Pointer(aOld[pi]), pln) then goto L; Inc(pi); end; end; end; c[off] := c^; Inc(c); Continue; L: Inc(c, pln); Dec(off, pln); pln := aNew[pi].Length; p := Pointer(aNew[pi]); for j := 0 to pln - 1 do c[off + j] := p[j]; Inc(off, pln); end; SetLength(Result, @c[off] - PChar(Pointer(Result))); end; -
Multiple string replace - avoid calling StringReplace multiple times
KodeZwerg replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Not faster, just tested. https://github.com/frones/ACBr/blob/master/Fontes/Terceiros/FastStringReplace/StrUtilsEx.pas Included as: uses StrUtilsEx; ... function StringReplaceExAll(const aStr: string; const aOldPatterns, aNewPatterns: array of string): string; var i: Integer; begin Result := aStr; for i := Low(aOldPatterns) to High(aOldPatterns) do Result := FastStringReplace(Result, aOldPatterns[i], aNewPatterns[i], [rfReplaceAll]); end; procedure RunTestCases(const aTestCases: TTestCases); var i: Integer; s, s7, s3, sSB, sEx: string; begin for i := Low(aTestCases) to High(aTestCases) do begin s := StringReplaceAll(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); s7 := ReplaceMultiStrings7(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); s3 := MultiStrReplace3(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); sSB := MultiStringReplaceSB(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); sEx := StringReplaceExAll(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); if (s <> s7) then raise Exception.Create('Not equal results: ' + sLineBreak + s + sLineBreak + s7); if (s <> s3) or (s <> sSB) then raise Exception.Create('Not equal results: ' + sLineBreak + s + sLineBreak + s3 + sLineBreak + sSB ); if (s <> sEx) then raise Exception.Create('Not equal results: ' + sLineBreak + s + sLineBreak + sEx); end; end; procedure DoTheTiming(const aCaption, aStr: string; const aOldPatterns, aNewPatterns: array of string); var vSW:TStopWatch; i: integer; str: string; begin Writeln(aCaption); // Standard StringReplace vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := StringReplaceAll(aStr, aOldPatterns, aNewPatterns); end; Writeln('StringReplaceAll: ' + vSW.ElapsedMilliseconds.ToString); // ReplaceMultiStrings7 vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := ReplaceMultiStrings7(aStr, aOldPatterns, aNewPatterns); end; Writeln('ReplaceMultiStrings7: ' + vSW.ElapsedMilliseconds.ToString); // MultiStrReplace3 vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := MultiStrReplace3(aStr, aOldPatterns, aNewPatterns); end; Writeln('MultiStrReplace3: ' + vSW.ElapsedMilliseconds.ToString); // MultiStringReplaceSB vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := MultiStringReplaceSB(aStr, aOldPatterns, aNewPatterns); end; Writeln('MultiStringReplaceSB: ' + vSW.ElapsedMilliseconds.ToString); // StringReplaceExAll vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := StringReplaceExAll(aStr, aOldPatterns, aNewPatterns); end; Writeln('StringReplaceExAll: ' + vSW.ElapsedMilliseconds.ToString); Writeln; end; With following Results Continue the journey.... -
Multiple string replace - avoid calling StringReplace multiple times
Leif Uneus replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
@Mike Torrettinni If you are looking for a faster Pos() function in 64-bit mode, see https://stackoverflow.com/a/20947429/576719 It is based on Fastcoders purepascal version. Just added some details to make it compile in 64-bit. -
New/old component re-released: TComPortDrv
TurboMagic replied to TurboMagic's topic in Delphi Third-Party
Small update: it is available via GetIt now for users of 10.4.1 and 10.4.2. Enjoy! -
Multiple string replace - avoid calling StringReplace multiple times
Dalija Prasnikar replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Delphi strings are pretty good as far as performance is concerned, TStringBuilder might have advantage when you need to handle longer strings and where benefits of preallocating buffer will outweigh the cost of the builder allocation, deallocation and try...finally block. I use TStringBuilder in few places, where it simplifies code, and I never measured the speed because it was not important in there. If you want to knock yourself out with micro-optimizations, you should definitely take a look at Knuth-Morris-Pratt algorithm, especially if you are matching same patterns over and over again https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm -
Multiple string replace - avoid calling StringReplace multiple times
KodeZwerg replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Yes! That one works cool! Will now checkout and try add own method! Thank you! -
Multiple string replace - avoid calling StringReplace multiple times
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Seems that when code is in SPOILER tags could be copied wrong. Here is latest source: program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Generics.Collections, System.Generics.Defaults, System.Diagnostics; type // Positions TSubStrPos = record Pos : integer; StrIdx: integer; end; // Test cases TTestCase = record Str: string; OldPatterns, NewPatterns: TArray<string>; end; TTestCases = TArray<TTestCase>; // Custom comparer initialized 1x only TCustomComparer = class(TInterfacedObject, IComparer<TSubStrPos>) public function Compare(const Left, Right: TSubStrPos): Integer; end; const cMaxLoop = 1000000; cShortA : string = 'abc < 1 > 2'; cMediumA : string = 'medium < text medium > text medium <> text medium text >'; cLongA : string = '<Lorem ipsum sit >amet, <consectetur adipiscing. Integer sagittis dolor a aliquam. >< Vestibulum et purus in dolor consectetur tempor a eget est. Curabitur sit amet erat imperdiet, <scelerisque >suscipit nisl. <Vestibulum velit.'; cShortB : string = 'testing and testing'; cMediumB : string = 'testing and testing and another testing and yet another testing of the test'; cLongB : string = 'Lorem te ipsum ingdolor sit stamet, consectetur adipiingiscing elitesting. Morbi bibendum, mauris Vestibulum vulputate, mauris neque pretium terisus, maximus odio ipsum vel est. Integer sollicitudin massa sit amet semper condimentum. rutrumingte'; cHTML: string = '<html><body>This is sample text for StringReplace test.' + 'Lorem <ipsum dolor sit amet,& consectetur adipiscing elit. Integer feugiat ullamcorper &ligula, at &vehicula turpis volutpat et. Praesent in sapien vel tortor pulvinar ullamcorper vel et felis. >Praesent mattis efficitur ligula, sit amet' + 'venenatis felis. Mauris dui mauris, tempus in turpis at, eleifend tincidunt arcu. Morbi nec tincidunt felis, non viverra nisi. Nulla facilisi.< Donec iaculis, elit >non hendrerit vehicula, urna dui efficitur &quolectus, in tempus metus est' + 'sed sem. <Vivamus eleifend euismod orci a volutpat. Ut sed ligula sed sem bibendum facilisis. Morbi gravida neque <nec odio lacinia, at tincidunt &nulla dignissim. Vestibulum vitae >nisi accumsan, dapibus lorem non, &quoconvallis turpis.' + 'Pellentesque imp&erdiet malesuada ipsum vel commodo. Nam dignissim< luctus augue, nec maximus felis vehicula eget. Phasellus ultrices lacus <ac elit dapibus &quopellentesque. Morbi vitae eros in turpis> hendrerit volutpat. Cras euismod' + ' dolor in scelerisque. Donec &id tincidunt nisi. Praesent ut nunc luctus, pulvinar <mauris ut, hend>rerit nulla. Praesent quis varius lorem.&' + '</body></html>'; cSpecialChars : string = 'Testing special char replacemenets: [Lorem te (ipsum) ing(((d)))olo/r -s+it st\\amet, co_!?nse?ctetur adipi-i!ng?isc/ing +(el_)i[_!?]testing.]'; var xComparer: IComparer<TSubStrPos>; function TCustomComparer.Compare(const Left, Right: TSubStrPos): Integer; begin Result := Left.Pos - Right.Pos; end; procedure GetSubStrPositions7(const aStr: string; const aOldPatterns, aNewPatterns: array of string; var aPositions: TArray<TSubStrPos>; var aFinalLength: integer); var vPos, i, vDiff, vIdx: integer; begin aFinalLength := aStr.Length; SetLength(aPositions, 32); vIdx := 0; for i := Low(aOldPatterns) to High(aOldPatterns) do begin vPos := Pos(aOldPatterns[i], aStr); vDiff := aNewPatterns[i].Length - aOldPatterns[i].Length; // calculate diff of replacements, to adjust aFinalLength while vPos <> 0 do begin if vIdx > High(aPositions) then SetLength(aPositions, Length(aPositions) * 2); aPositions[vIdx].Pos := vPos; aPositions[vIdx].StrIdx := i; Inc(vIdx); aFinalLength := aFinalLength + vDiff; vPos := Pos(aOldPatterns[i], aStr, vPos + 1); end; end; SetLength(aPositions, vIdx); end; function ReplaceMultiStringsByPositions7(const aStr: string; const aPositions: TArray<TSubStrPos>; const aOldPatterns, aNewPatterns: array of string; aResultLen: integer): string; var i, vResPos, vStrPos: Integer; begin SetLength(Result, aResultLen); // move substrings by index + between indexes, if any vResPos := 1; vStrPos := 1; for i := Low(aPositions) to High(aPositions) do begin // Copy free text between last Pos and current Pos if aPositions[i].Pos > vStrPos then begin Move(aStr[vStrPos], Result[vResPos], (aPositions[i].Pos - vStrPos)*SizeOf(Char)); Inc(vResPos, aPositions[i].Pos - vStrPos); end; // copy New str Move(aNewPatterns[aPositions[i].StrIdx][1], Result[vResPos], aNewPatterns[aPositions[i].StrIdx].Length * SizeOf(Char)); // move Pos by New str len Inc(vResPos, aNewPatterns[aPositions[i].StrIdx].Length); // move aStr Pos vStrPos := aPositions[i].Pos + aOldPatterns[aPositions[i].StrIdx].Length; end; // copy any left after last replacement if vStrPos < aStr.Length then Move(aStr[vStrPos], Result[vResPos], (aStr.Length - vStrPos + 1) * SizeOf(Char)); end; procedure SortPositions(var aPositions: TArray<TSubStrPos>); begin if xComparer = nil then xComparer := TCustomComparer.Create; // initialize Comparer TArray.Sort<TSubStrPos>(aPositions, xComparer); end; procedure InsertionSort(var A: TArray<TSubStrPos>); var i, j: Integer; tmp: TSubStrPos; begin for i:= 1 to high(A) do begin j:= i; tmp := A[i]; while (j > 0) and (A[j-1].Pos > tmp.Pos) do begin A[j]:= A[j-1]; Dec(j); end; A[j]:= tmp; end; end; function ReplaceMultiStrings7(const aStr: string; const aOldPatterns, aNewPatterns: array of string): string; var vPositions: TArray<TSubStrPos>; vResultLen: integer; // vPositions2: TArray<TSubStrPos>; begin // Get Positions for all string replacements GetSubStrPositions7(aStr, aOldPatterns, aNewPatterns, vPositions, vResultLen); //GetSubStrPositions7(aStr, aOldPatterns, aNewPatterns, vPositions2, vResultLen); // Sort Positions so the replacements go from first to last pos //SortPositions(vPositions); InsertionSort(vPositions); // Insertion sort is faster in these situation because of small number of items to sort // Replace by indexes Result := ReplaceMultiStringsByPositions7(aStr, vPositions, aOldPatterns, aNewPatterns, vResultLen); end; { Standard StringReplace used multiple times } function StringReplaceAll(const aStr: string; const aOldPatterns, aNewPatterns: array of string): string; var i: Integer; begin Result := aStr; for i := Low(aOldPatterns) to High(aOldPatterns) do Result := StringReplace(Result, aOldPatterns[i], aNewPatterns[i], [rfReplaceAll]); end; function MultiStrReplace3(const aStr: string; const aOldPatterns, aNewPatterns: array of string): string; var vCharPos: integer; vStrLen: integer; i, j, vStrPos: integer; vMatched: boolean; vResPos, a, b: integer; begin vStrLen := Length(aStr); if vStrLen > 0 then begin SetLength(Result, 2 * vStrLen); // pre-allocate Result vStrPos := 1; vCharPos := 1; vResPos := 1; a := Low(aOldPatterns); b := High(aOldPatterns); while vCharPos <= vStrLen do begin // find next match for i := a to b do begin vMatched := false; if (aStr[vCharPos] = aOldPatterns[i][1]) then begin vMatched := True; for j := 1 to aOldPatterns[i].Length - 1 do if aStr[vCharPos + j] <> aOldPatterns[i][j+1] then begin vMatched := false; Break; end; end; // replace matched string if vMatched then begin // add original string up to this point, if needed Move(aStr[vStrPos], Result[vResPos], (vCharPos - vStrPos)*SizeOf(Char)); Inc(vResPos, vCharPos - vStrPos); // now add new string Move(aNewPatterns[i][1], Result[vResPos], (aNewPatterns[i].Length)*SizeOf(Char)); Inc(vResPos, aNewPatterns[i].Length); // move pos past the matched string Inc(vCharPos, aOldPatterns[i].Length); vStrPos := vCharPos; Break; end; end; if not vMatched then inc(vCharPos) else vMatched := false; end; // add end of string Move(aStr[vStrPos], Result[vResPos], (aStr.Length - vStrPos +1)*SizeOf(Char)); SetLength(Result, vResPos + (aStr.Length - vStrPos)); end; end; function MultiStringReplaceSB(const aStr: string; const aOldPatterns, aNewPatterns: array of string): string; var vSB: TStringBuilder; vCharPos: integer; vStrLen: integer; i, j, vStrPos: integer; vMatched: boolean; a, b: integer; begin vStrLen := Length(aStr); if vStrLen > 0 then begin vSB := TStringBuilder.Create( 2 * Length(aStr)); try vStrPos := 1; vCharPos := 1; a := Low(aOldPatterns); b := High(aOldPatterns); while vCharPos <= vStrLen do begin // find next match for i := a to b do begin vMatched := false; if (aStr[vCharPos] = aOldPatterns[i][1]) then begin vMatched := True; for j := 1 to aOldPatterns[i].Length - 1 do if aStr[vCharPos + j] <> aOldPatterns[i][j+1] then begin vMatched := false; Break; end; end; // replace matched string if vMatched then begin // add original string up to this point, if needed vSB.Append(Copy(aStr, vStrPos, vCharPos - vStrPos)); // now add new string vSB.Append(aNewPatterns[i]); // move pos past the matched string Inc(vCharPos, aOldPatterns[i].Length); vStrPos := vCharPos; Break; end; end; if not vMatched then inc(vCharPos) else vMatched := false; end; // add end of string vSB.Append(Copy(aStr, vStrPos, aStr.Length - vStrPos +1)); Result := vSB.ToString; finally vSB.Free; end; end; end; { Test cases } procedure AddTestCase(var aTestCases: TTestCases; const aStr: string; const aOldPatterns, aNewPatterns: TArray<string>); var vTestCase: TTestCase; begin vTestCase.Str := aStr; vTestCase.OldPatterns := aOldPatterns; vTestCase.NewPatterns := aNewPatterns; aTestCases := aTestCases + [vTestCase]; end; procedure RunTestCases(const aTestCases: TTestCases); var i: Integer; s, s7, s3, sSB: string; begin for i := Low(aTestCases) to High(aTestCases) do begin s := StringReplaceAll(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); s7 := ReplaceMultiStrings7(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); s3 := MultiStrReplace3(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); sSB := MultiStringReplaceSB(aTestCases[i].Str, aTestCases[i].OldPatterns, aTestCases[i].NewPatterns); if (s <> s7) then raise Exception.Create('Not equal results: ' + sLineBreak + s + sLineBreak + s7); if (s <> s3) or (s <> sSB) then raise Exception.Create('Not equal results: ' + sLineBreak + s + sLineBreak + s3 + sLineBreak + sSB ); end; end; procedure DoTheTiming(const aCaption, aStr: string; const aOldPatterns, aNewPatterns: array of string); var vSW:TStopWatch; i: integer; str: string; begin Writeln(aCaption); // Standard StringReplace vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := StringReplaceAll(aStr, aOldPatterns, aNewPatterns); end; Writeln('StringReplaceAll: ' + vSW.ElapsedMilliseconds.ToString); // ReplaceMultiStrings7 vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := ReplaceMultiStrings7(aStr, aOldPatterns, aNewPatterns); end; Writeln('ReplaceMultiStrings7: ' + vSW.ElapsedMilliseconds.ToString); // MultiStrReplace3 vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := MultiStrReplace3(aStr, aOldPatterns, aNewPatterns); end; Writeln('MultiStrReplace3: ' + vSW.ElapsedMilliseconds.ToString); // MultiStringReplaceSB vSW := TStopWatch.StartNew; for i := 1 to cMaxLoop do begin str := ''; str := MultiStringReplaceSB(aStr, aOldPatterns, aNewPatterns); end; Writeln('MultiStringReplaceSB: ' + vSW.ElapsedMilliseconds.ToString); Writeln; end; var vTestCases: TTestCases; begin // make sure string replacement is correct! AddTestCase(vTestCases, cShortA, ['<', '>'], ['<', '>']); AddTestCase(vTestCases, cMediumA, ['<', '>'], ['<', '>']); AddTestCase(vTestCases, cLongA, ['<', '>'], ['<', '>']); AddTestCase(vTestCases, cShortB, ['te', 'st', 'ing', 'and'], ['ab', 'cd', 'ef', 'AND']); AddTestCase(vTestCases, cShortB, ['te'], ['AND']); AddTestCase(vTestCases, cShortB, ['and'], ['ab']); AddTestCase(vTestCases, cMediumB, ['te', 'st', 'ing', 'and'], ['ab', 'cd', 'ef', 'AND']); AddTestCase(vTestCases, cMediumB, ['te'], ['AND']); AddTestCase(vTestCases, cMediumB, ['and'], ['ab']); AddTestCase(vTestCases, cLongB, ['te', 'st', 'ing', 'and'], ['ab', 'cd', 'ef', 'AND']); AddTestCase(vTestCases, cLongB, ['te'], ['AND']); AddTestCase(vTestCases, cLongB, ['and'], ['ab']); AddTestCase(vTestCases, cHTML, ['<', '>', '&', '"'], ['<', '>', '&', '"']); AddTestCase(vTestCases, cSpecialChars, ['\', '/', '!', '?', '[', ']', '_', '(', ')', '-', '+'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']); // Examples of different outcome between calling StringReplace multiple times vs one-time replace all substrings //AddTestCase(vTestCases, 'ReplaceReplaceString', ['Replace', 'FooString'], ['Foo', 'Bar']); RunTestCases(vTestCases); // DoTheTiming('Short str A:', cShortA, ['<', '>'], ['<', '>']); // DoTheTiming('Medium str A:', cMediumA, ['<', '>'], ['<', '>']); // DoTheTiming('Long str A:', cLongA, ['<', '>'], ['<', '>']); DoTheTiming('Short str B:', cShortB, ['te', 'st', 'ing', 'and'], ['ab', 'cd', 'ef', 'AND']); DoTheTiming('Medium str B:', cMediumB, ['te', 'st', 'ing', 'and'], ['ab', 'cd', 'ef', 'AND']); DoTheTiming('Long str B:', cLongB, ['te', 'st', 'ing', 'and'], ['ab', 'cd', 'ef', 'AND']); DoTheTiming('HTML:', cHTML, ['<', '>', '&', '"'], ['<', '>', '&', '"']); DoTheTiming('Special Chars:', cSpecialChars, ['\', '/', '!', '?', '[', ']', '_', '(', ')', '-', '+'], ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']); Writeln('done...'); Readln; end. -
Multiple string replace - avoid calling StringReplace multiple times
KodeZwerg replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Pictures say more than a thousand words, so I append some 😉 -
Of course it would. It is just that all others are completely incompetent. 🤦♂️
-
Multiple string replace - avoid calling StringReplace multiple times
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Whether you decide is up to your own spec, but according to your testcase its a defect 🤷♂️ -
It was pretty daunting for me: Native Camera for iOS and Android – Delphi Worlds There's still a number of issues to resolve...
-
Delphi Developers Archive (Experimental)
Lars Fosdal posted a topic in Tips / Blogs / Tutorials / Videos
Delphi Developers Archive (Experimental) for the Google + Delphi Developers Community is online. https://delphi-developers-archive.blogspot.com The posts are searchable by tag list or free text search. FYI - This is work in progress, and I hope to improve the following issues: - Some posts have erroneous titles - Some posts are missing attribution of the original poster - Some 600 posts are missing due to an inexplicable quota error during import Comments on the archived posts are currently disabled until the import is finalized. Comments appreciated.