TMemo string sort optimizing [Edit]

Hello. Can somebody help me (if it's possible) to optimize my shitty code for a "thanks"? Because the more string there are the more time it takes (in geometrical progression).
{code}
procedure ReplaceDots(InStr: string;i:integer);
var S: string;
begin
 S :=InStr;
 while Pos('.', S) > 0 do S[Pos('.', S)] := ',';
 Form1.Memo1.Lines[i]:=S;
end;
{code}

{code}
procedure ReplaceQuotes(InStr: string;i:integer);
var temp:String;
begin
temp:='"';
while Pos(temp,InStr) > 0 do Delete(InStr,Pos(temp,InStr),1);
Form1.Memo1.Lines[i]:=InStr;
end;
{code}

{code}
procedure FormatInput;
var
 LinesCount:Integer;
 i:Integer;
 s:string;
 Cursor:TCursor;
begin
 Cursor:=Screen.Cursor;
 LinesCount:=Form1.Memo1.Lines.Count;
 for i:=0 to LinesCount do
  begin
  Application.ProcessMessages;
   Screen.Cursor:=crHourGlass;
   Form1.Label1.Caption:='Please wait. '+IntToStr(LinesCount-i)+' lines to go';
   if ((LeftStr(Form1.Memo1.Lines[i],3)='R01') or (LeftStr(Form1.Memo1.Lines[i],3)='901')) then
    begin
     Application.ProcessMessages;
     ReplaceDots(Form1.Memo1.Lines[i],i);
     s:=Form1.Memo1.Lines[i];
     Delete(s,(Length(s)-7),8);
     Form1.Memo1.Lines[i]:=s;
     ReplaceQuotes(Form1.Memo1.Lines[i+2],i+2);
    end; // end IF
 Screen.Cursor:=Cursor;
end; // end FOR
Form1.Label1.Caption:='Done!';
end;
{code}

Edited by: Serhij Gajdosh on Aug 11, 2015 1:10 AM
0
Serhij
8/11/2015 8:21:11 AM
embarcadero.delphi.vcl.using 2297 articles. 1 followers. Follow

5 Replies
385 Views

Similar Articles

[PageSpeed] 23

Serhij wrote:

> procedure ReplaceDots(InStr: string;i:integer);
> var S: string;
> begin
> S :=InStr;
> while Pos('.', S) > 0 do S[Pos('.', S)] := ',';
> Form1.Memo1.Lines[i]:=S;
> end;

Remove redundant calls to Pos() that are searching the same sections of the 
string over and over unnecessarily:

{code}
uses
  ..., StrUtils;

procedure ReplaceDots(const InStr: string; i: Integer);
var
  S: string;
  J: Integer;
begin
  S := InStr;
  J := Pos('.', S);
  while J > 0 do
  begin
    S[J] := ',';
    J := PosEx('.', S, J+1);
  end;
  Form1.Memo1.Lines[i] := S;
end;
{code}

Or simpler:

{code}
uses
  ..., SysUtils;

procedure ReplaceDots(const InStr: string; i: Integer);
begin
  Form1.Memo1.Lines[i] := StringReplace(InStr, '.', ',', [rfReplaceAll]);
end;
{code}

> procedure ReplaceQuotes(InStr: string;i:integer);
> var temp:String;
> begin
> temp:='"';
> while Pos(temp,InStr) > 0 do Delete(InStr,Pos(temp,InStr),1);
> Form1.Memo1.Lines[i]:=InStr;
> end;

Same thing:

{code}
uses
  ..., StrUtils;

procedure ReplaceQuotes(const InStr: string; i: integer);
var
  J: Integer;
begin
  S := InStr;
  J := Pos('"', S);
  while J > 0 do
  begin
    Delete(S, J, 1);
    J := PosEx('"', S, J);
  end;
  Form1.Memo1.Lines[i] := S;
end;
{code}

Or:

{code}
uses
  ..., SysUtils;

procedure ReplaceQuotes(const InStr: string; i: integer);
begin
  Form1.Memo1.Lines[i] := StringReplace(InStr, '"', '', [rfReplaceAll]);
end;
{code}

> procedure FormatInput;

There are a lot of things you can clean up in this function.  Try something 
like this:

{code}
uses
  ..., SysUtils;

function ReplaceDots(const InStr: string): string;
begin
  Result := StringReplace(InStr, '.', ',', [rfReplaceAll]);
end;

function ReplaceQuotes(const InStr: string): string;
begin
  Result := StringReplace(InStr, '"', '', [rfReplaceAll]);
end;

procedure FormatInput;
var
  LinesCount: Integer;
  i: Integer;
  s: string;
  Cursor: TCursor;
begin
  Cursor := Screen.Cursor;
  try
    Screen.Cursor := crHourGlass;
    Application.ProcessMessages;
    Form1.Memo1.Lines.BeginUpdate;
    try
      LinesCount := Form1.Memo1.Lines.Count;
      for i := 0 to LinesCount-1 do
      begin
        Form1.Label1.Caption := 'Please wait. ' + IntToStr(LinesCount-i) 
+ ' lines to go';
        Form1.Label1.Update;
        s := Form1.Memo1.Lines[i];
        if (LeftStr(s, 3) = 'R01') or (LeftStr(s, 3) = '901') then
        begin
          s := ReplaceDots(s);
          Form1.Memo1.Lines[i] := Copy(s, 1, Length(s)-8);
          if (i+2) < LinesCount then
            Form1.Memo1.Lines[i+2] := ReplaceQuotes(Form1.Memo1.Lines[i+2]);
        end; // end IF
      end; // end FOR
    finally
      Form1.Memo1.Lines.EndUpdate;
    end;
  finally
    Screen.Cursor := Cursor;
  end;
  Form1.Label1.Caption := 'Done!';
end;
{code}

Alternatively:

{code}
uses
  ..., SysUtils, StrUtils;

function ReplaceDots(var InStr: string): Boolean;
var
  J: Integer;
begin
  Result := False;
  J := Pos('.', InStr);
  if J > 0 then
  begin
    Result := True;
    repeat
      InStr[J] := ',';
      J := PosEx('.', InStr, J+1);
    until J = 0;
  end;
end;

function ReplaceQuotes(var InStr: string): Boolean;
var
  J: Integer;
begin
  Result := False;
  J := Pos('"', InStr);
  if J > 0 then
  begin
    Result := True;
    repeat
      Delete(InStr, J, 1);
      J := PosEx('"', InStr, J);
    until J = 0;
  end;
end;

procedure FormatInput;
var
  LinesCount: Integer;
  i: Integer;
  s: string;
  Cursor: TCursor;
begin
  Cursor := Screen.Cursor;
  try
    Screen.Cursor := crHourGlass;
    Application.ProcessMessages;
    Form1.Memo1.Lines.BeginUpdate;
    try
      LinesCount := Form1.Memo1.Lines.Count;
      for i := 0 to LinesCount-1 do
      begin
        Form1.Label1.Caption := 'Please wait. ' + IntToStr(LinesCount-i) 
+ ' lines to go';
        Form1.Label1.Update;
        s := Form1.Memo1.Lines[i];
        if (LeftStr(s, 3) = 'R01') or (LeftStr(s, 3) = '901') then
        begin
          if ReplaceDots(s) then
            Form1.Memo1.Lines[i] := Copy(s, 1, Length(s)-8);
          if (i+2) < LinesCount then
          begin
            s := Form1.Memo1.Lines[i+2];
            if ReplaceQuotes(s) then
              Form1.Memo1.Lines[i+2] := s;
          end;
        end; // end IF
      end; // end FOR
    finally
      Form1.Memo1.Lines.EndUpdate;
    end;
  finally
    Screen.Cursor := Cursor;
  end;
  Form1.Label1.Caption := 'Done!';
end;
{code}

-- 
Remy Lebeau (TeamB)
0
Remy
8/11/2015 5:20:43 PM
Remy Lebeau (TeamB) wrote:

> Or simpler:
.... 
>   StringReplace(InStr, '.', ',', [rfReplaceAll]);

From my personal experience (2007) StringReplace is _very_ slow for
(very) long strings.

If it is possible to replace a symbol "on place" (as in this case) it's
better to use simple 'for' loop to scan and replace chars (even without
using Pos function).

--
Alex
0
Alex
8/12/2015 4:07:39 AM
Serhij Gajdosh wrote:

> Hello. Can somebody help me (if it's possible) to optimize my shitty
> code for a "thanks"? Because the more string there are the more time
> it takes (in geometrical progression).  

Well, the first thing you should change is to copy the content of the
memo to a TStringlist, do all modifications on this copy, and finally
copy the modified content back to the memo. Getting lines from a memo
and putting them back is way slower than doing the same operations on a
TStringlist.

You also failed to tell us which Delphi version you are using. There
has been a StringReplace function in Sysutils for many versions now
which you can use to replace your while loops, for example.

You seem to have some experience with Basic for string manipulations,
which gets in your way in this case. If you are writing code for a
Windows application only you can directly work with characters in a
string, as if it were an array of characters.

>  while Pos('.', S) > 0 do S[Pos('.', S)] := ',';

can thus be written as
   
   for I:= 1 to Length(S) do
     if S[I] = '.' then S[I] := ',';

or shorter
  
   S:= StringReplace(Instr, '.', ',', [rfReplaceAll]);

This avoids two calls to Pos for each loop. The for loop variant is
propably faster than Stringreplace, which is not written very
efficiently, unfortunately.

> {code}
> procedure ReplaceQuotes(InStr: string;i:integer);
> var temp:String;
> begin
> temp:='"';
> while Pos(temp,InStr) > 0 do Delete(InStr,Pos(temp,InStr),1);
 
   InStr := Stringreplace(Instr, temp, '', [rfReplaceAll]);

>  if ((LeftStr(Form1.Memo1.Lines[i],3)='R01') or
(LeftStr(Form1.Memo1.Lines[i],3)='901')) then

In such a case it pays to introduce a local string variable to hold the
line you work on:
The Strutils unit also contains a StartsStr function that comes in
handy here:

  Line := Form1.Memo1.Lines[i];
  if StartsStr('R01', Line) or StartsStr('901', Line) then
  ...

This way you avoid a call to the getter for the Memo1.Lines property,
which is quite costly for a TMemo.

> LinesCount:=Form1.Memo1.Lines.Count;
 >for i:=0 to LinesCount do

You have an off-by-one error here, the last line has index LinesCount-1.

The way you constructed your code also ties it firmly to form1, and
that makes any reuse for another set of lines impossible. This is a
good opportunity to refactor all this code to a small helper class,
which you can put into its own unit and use anywhere you need to
perform such cleanup on a set of lines held in a TStrings descendent
(TMemo.Lines is such a descendent).

With the following unit you would just add that to the form Uses clause
(in the implementation section), and call

  FormatInput(Memo1.Lines);

from one of the form's methods.

{code: Delphi}
unit InputFormatterU;

interface

uses
  Classes;

procedure FormatInput(aInput: TStrings);

implementation

uses
  Sysutils, StrUtils;

const
  Dot = '.';
  Comma = ',';
  DoubleQuote = '"';

type
  TInputFormatter = class
  private
    FResults: TStringlist;
    function RemoveQuotes(const aInStr: string): string;
    procedure ReplaceDots(var Line: string);
  public
    constructor Create(aInput: TStrings);
    destructor Destroy; override;
    class procedure Execute(aInput: TStrings);
    procedure Run;
    property Results: TStringlist read FResults;
  end;

procedure FormatInput(aInput: TStrings);
begin
  TInputFormatter.Execute(aInput);
end;

constructor TInputFormatter.Create(aInput: TStrings);
begin
  inherited Create;
  FResults := TStringlist.Create;
  FResults.Assign(aInput);
end;

destructor TInputFormatter.Destroy;
begin
  FResults.Free;
  inherited Destroy;
end;

class procedure TInputFormatter.Execute(aInput: TStrings);
var
  LFormatter: TInputFormatter;
begin
  LFormatter := TInputFormatter.Create(aInput);
  try
    LFormatter.Run;
    aInput.Assign(LFormatter.Results);
  finally
    LFormatter.Free;
  end;
end;

function TInputFormatter.RemoveQuotes(const aInStr: string): string;
var
  I, N: integer;
begin
  SetLength(Result, Length(aInStr));
  N:=1;
  for I := 1 to Length(aInStr) do
    if aInStr[I] <> DoubleQuote then begin
      Result[N] := aInStr[I];
      Inc(N);
    end;
  SetLength(Result, N-1);
end;

procedure TInputFormatter.ReplaceDots(var Line: string);
var
  I: integer;
begin
 for I:= 1 to Length(Line) do
   if Line[I] = Dot then Line[I] := Comma;
end;

procedure TInputFormatter.Run;
var
  I: Integer;
  Line: string;
begin
  for I := 0 to FResults.Count-1 do begin
    Line := FResults[I];
    if StartsStr('R01', Line) or StartsStr('901', Line) then begin
      ReplaceDots(Line);
      SetLength(Line, Length(Line)-8);
      // SetLength is faster than Delete to cut chars off the end
      // Delete(Line,(Length(Line)-7),8);
      FResults[I] := Line;
      if (I+2) < FResults.Count then
        FResults[I+2] := RemoveQuotes(FResults[I+2]);
    end;
  end;
end;

end.
{code}








-- 
Peter Below (TeamB)
0
Peter
8/12/2015 8:32:54 AM
Alex wrote:

> From my personal experience (2007) StringReplace is _very_ slow
> for (very) long strings.

Perhaps.  In that case, since a single character is being replaced with another 
single character, a simple iteration would suffice, as shown in my other 
examples.

> If it is possible to replace a symbol "on place" (as in this case)
> it's better to use simple 'for' loop to scan and replace chars
> (even without using Pos function).

You could, but why not use Pos/Ex() for the iteration?  The only thing to 
watch out for is that Pos/Ex() requires a String as input for the substring 
to look for, so if you pass a single Char as input than a runtime conversion 
occurs.  But in my earlier examples, literals are being passed to Pos/Ex(), 
and the compiler knows to treat a single-character literal as a String and 
not as a Char when it is passed to a String variable/parameter.

-- 
Remy Lebeau (TeamB)
0
Remy
8/12/2015 5:02:58 PM
Remy Lebeau (TeamB) wrote:

> why not use Pos/Ex() for the iteration?

To save (many) function calls. It can be faster but it requires
benchmarking: Pos can be faster (due to coding in asm) than simple
'for' if 1) string is big and 2) number of occurrences is relatively
small.

--
Alex
0
Alex
8/13/2015 3:52:42 AM
Reply:

Similar Artilces:

Delphi XE2, Indy 10
Dear folks The following code is supposed to send a text string to a client that is listening on a set port and ip address. The connection works fine. The problem is that nothing seems to be sent. {code} function TFCSelectForm.SendNitroMessage(NitroRequest: String): String; var sStrm: TMemoryStream; begin try sStrm := TMemoryStream.Create; try sStrm.WriteBuffer(Pointer(NitroRequest)^,Length(NitroRequest)); // sStrm shows as () in the debugger IdTCPClient1.IOHandler.Write(sStrm, 0, False); sStrm.Position := 0; finally ...

Cannot use Microsoft Excel when a Delphi application that uses automat. run [Edit]
Dear all, I built an application that connect to an Excel file using a OleObject: Excel := CreateOleObject('Excel.Application'); LCID := GetUserDefaultLCID; all works fine but I cannot use Microsoft Excel externally when my application is running. If I try to open another xls file, Excel tries to open the file in my Delphi application in read only mode. It does not even show it properly but opens a weir transparent application. I just want to be able to use Excel externally and I'd like the instance opened by my Delphi application to be independent from other Exc...

Problem using InstallAware 7 CodeGear Special Edition with Delphi 2010 [Edit]
Hi Everyone, I am trying to create an installation disk for my delphi 2010 application using the installAware that kind of comes with Delphi 2010. When I try to built it, it keeps giving me the error message:- No files matching pattern "C:\Windows\system32\\*120.bpl" and when I look into my windows\system32 folder, there the files with extension *.bpl end with *140.bpl and not *120.bpl like it was expected. Can anyone tell me if I am doing something wrong or how I can get around this. Thanks in advance. Edited by: Tat Hon Chu on Dec 3, 2009 12:55 AM > {quo...

To use or not to use Delphi
Sadly, it seems to me that there is a sort of race between the two threads, for and against using Delphi in new projects, with more or less the same users posting in both threads. Arguments are fiercely debated in both camps. Borland had their own vision. As a community, now that Delphi has changed ownership I believe we should try to be more consistent, more clear, and more articulate in what we expect from Embercadero in terms of Delphi. We can contribute to keeping Delphi alive and moving in the right direction. "Laurent Cocea" schrieb: > Sadly, it seems to me that there ...

Delphi
Hi, I'm trying to make an application that connects to the specyfic device and read some data... thay are in strings... Device producer give Delphi library that works but instead of number (string with number '1234.67') I get kind of chinesse letters.. if I do AnsiString := String there is '??????d' string instead od chinnesse :-) with other string I get without last letter i.e.: 'Unknow'. http://i.imgur.com/jP47wgC.png The library was made for Delphi 7 and is open in XE5... In future I'd like to use it in FMX also... Sebastian wrote: > I&#...

ANN: The free to use kbmMW 3.51.00 CodeGear Edition and kbmMemTable v. 7.00.01 Beta 1 CodeGear Edition for Delphi XE, has been released!
We are happy to announce the immediate availability of the free to use kbmMW v. 3.51.00 CodeGear Edition and kbmMemTable v. 7.00.01 CodeGear Edition for Delphi XE! The keywords for this release are: - Delphi XE support - Highly optimized performance in master/detail and ranges in kbmMemTable. - New GroupBy function in kbmMemTable. - Improved support for fielddefinitions with data, even in master/detail relations - Performance enhancements - Multithreading enhancements - Dataset enhancements - Stability enhancements and bugfixes Remember the free kbmMemTable CodeGear Edition ...

Trying to use the FAQ " Sorting and paging in the GridView control when not using data source controls "Sorting and paging in the GridView control when not using..."
and I am not getting the results I had hoped for.  I keep getting a "Compiler Error Message: CS0123: No overload for 'AdhocJobGridView_PageIndexChanged' matches delegate 'System.EventHandler'".   Here is my event handling... protected void AdhocJobGridView_PageIndexChanged(object sender, GridViewPageEventArgs e){ try { AdhocJobGridView.DataSource = wsBaseInfoArray; AdhocJobGridView.PageIndex = e.NewPageIndex; AdhocJobGridView.DataBind(); }catch (Exception ex) {throw ex; }   Here is my aspx... <asp:GridView ID="AdhocJobGridView...

How to transform an XML string using a XSLT string without using files?
I am sure I am being a muppet, but I don't seem to be able to find a simple method of doing this and all examples use seperated files especially for the XSLT file. Overview ----------------------------- Basically I have a custom control which gets data from xml and sql server. The data is currently displayed using templated interfaces, but XSLT transformations are now required. Now I do not want a new XSLT file for every instance of the control, and so I have created a public function for the XSLT to be entered. This is all great but I can't find a method of doing the tra...

Using WordApplication in Delphi 2010 [Edit]
Hello Everyone, I am having a problem with WordApplicatio component. I am using Delphi 10. I can get the WordApplication to open with the Document template that I select, but Word is behind my app and when I close Word I get an RPC Server not available errror and after that a pointer violation and then access violations until I reset the IDE. Here is the code I am using: procedure TTestLetterForm.Button1Click(Sender: TObject); var FileName: oleVariant; begin //Letter2Report.Print; if OpenDialog.Execute = True then begin FileName := OpenDialog.Fil...

How can you guys use Delphi? :) [Edit]
This message is no longer available. Seems that my post was deleted. (Rudy don't you have anything more useful to do?) So here it goes: Every few years I take the current updated version of Delphi for a test drive and go back to Delphi7. This time I installed Xe3 and compiled my project. Gee, the resulting program was full of flickers. A brief mouse cursor move on controls to show the hints left black rectangles on the GUI :D and the exe grew from 3.08 MB to 5.57 MB. By the way, am I right to think that all versions since D7 are tied to different dotnet versions? Edited by: Bob ...

how to use paging, sorting and edit in DataGrid???
Hi...!,       I would like to add paging, sorting and edit to the Datagrid.  I have set the Allowpaging and Allowsorting attribute of the DataGrid  to true. What else should i do??? What code should be written  in codebehind c# ? Also i need to edit the details of a particular record when i click the edit in the Datagrid, how could this be done??? Please help me with the appropriate code. I have given my .aspx and .cs  code below. ASPX code : <body MS_POSITIONING="GridLayout">  <form id="Fo...

Delphi long string, not RAD.. at all [Edit]
Hi, I'm using Delphi XE8, but this apply to the very first turbo pascal 1.0 <g> The delphi way to handle long string ( more than 255 chars ) is to split with '+' in each line. {code} const _my_long_string = 'Some line'+ 'Some Another line'+ 'Some extra line'+ .... 'Last one'; {code} In database application, some queries have 220 lines that must be combined with "%s" and "%d" and someti...

How to use IThumbnailProvider in Delphi 2010? [Edit]
Hello, I try to use IThumbnailProvider for getting thumbnail from the file. I can not get ThumbnailProvider, the result of the line "result := fileShellItem.BindToHandler(nil, BHID_ThumbnailHandler, IID_IThumbnailProvider, thumbProvider );" is always false. Could someone help me? Regards Eric P.S. I use Win7/64 type {$EXTERNALSYM IThumbnailProvider} IThumbnailProvider = interface(IUnknown) ['{e357fccd-a995-4576-b01f-234630154e96}'] function GetThumbnail(cx : uint; out hBitmap : HBITMAP; out bitmapType : dword):HRESULT;stdcall; end; const ...

How to sort records in Delphi DBGrid [Edit]
I need to alphabetically sort records in the TDBGrid at run-time I don't want to sort records from the Table or Dataset because that is my main sort index. I can't seem to work this out can someone help please? I am using Delphi 7 it really works for me. Edited by: unit4 P on Aug 11, 2012 3:10 PM Edited by: unit4 P on Aug 11, 2012 4:38 PM On 12/08/2012 9:38 AM, unit4 P wrote: > I need to alphabetically sort records in the TDBGrid at run-time > I don't want to sort records from the Table or Dataset because that is my main sort index. > > I can't se...

Web resources about - TMemo string sort optimizing [Edit] - embarcadero.delphi.vcl.using

Optimizing compiler - Wikipedia, the free encyclopedia
In computing , an optimizing compiler is a compiler that tries to minimize or maximize some attributes of an executable computer program. The ...

INFOGRAPHIC: Optimizing Images To Get Through Facebook’s News Feed Algorithm
Many Facebook marketers agree that images are the most powerful type of posts for pages seeking engagement. But with Facebook’s page post sorting ...

Tips on Optimizing Facebook Ads for Affiliate E-Commerce Sales
This is a guest post by Kunal Kripalani , who most recently led marketing strategy for Australia’s biggest online bookstore, Fishpond . Kripalani ...

iContrast Free - the best image contrast / brightness optimizing app on the App Store on iTunes
Get iContrast Free - the best image contrast / brightness optimizing app on the App Store. See screenshots and ratings, and read customer reviews. ...

#Techonomy2015 discussion at minute 20 in the video: http://techonomy.com/conf/te15/videos-human-val ...
jurvetson posted a photo: Are we optimizing the future? The Techonomy2015 discussion with Jaron Lanier and Sir Colin Blakemore. We begin the ...

OptiCon 2014: Optimizing Your Optimization Strategy - YouTube
Kyle Rush, Head of Optimization at Optimizely Benn Stancil, Co-Founder and Chief Analyst at Mode In this session Kyle Rush, Head of Optimization ...

Optimizing the Sustainable Pace
Sustainable pace is an early Extreme Programming concept that was intended to protect programmers from going on “death marches” to meet deadlines ...

Optimizing Your Pinterest Profile
... is the right time to optimize your Pinterest account if you have one. Why Pinterest Profile Optimization is Important One reason why optimizing ...

INFOGRAPHIC: Why Facebook Pages Should Be Optimizing Their Images For News Feed
There have been several image-sizing guides for page posts , but, as McBeard Media pointed out, 99 percent of Facebook user impressions occur ...

Blizzard further optimizing 'Diablo III' for MacBook Pro Retina display
Though the blockbuster game "Diablo III" currently runs on the new MacBook Pro at the native resolution of its Retina display, developer Blizzard ...

Resources last updated: 12/6/2015 7:01:58 AM