powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Быстрая замена символа
25 сообщений из 259, страница 2 из 11
Быстрая замена символа
    #39676424
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоФи
Код: pascal
1.
2.
3.
4.
5.
6.
 while P^ <> #0 do 
  begin
    if P^ = Source then
        P^ := Target;
     Inc(P);
  end;


В теории - да, быстрее на один вызов Length. Однако опирается на постулат, что все строки заканчиваются нулевым символом, что, емнип, не документировано. Также не прожуёт строки с нулевым символом внутри (а это, к примеру, способ задания массива строк в WinApi).
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676429
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zinpubЯ её допеределывал, чуууть медленнее асма
Вот и славно :)
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676432
zinpub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Василий 2ГирлионайльдоФи
Код: pascal
1.
2.
3.
4.
5.
6.
 while P^ <> #0 do 
  begin
    if P^ = Source then
        P^ := Target;
     Inc(P);
  end;


В теории - да, быстрее на один вызов Length. Однако опирается на постулат, что все строки заканчиваются нулевым символом, что, емнип, не документировано. Также не прожуёт строки с нулевым символом внутри (а это, к примеру, способ задания массива строк в WinApi).

Лишнее чтение на каждой итерации
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676433
Фотография Dmitry Arefiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
PEnd := P + Length(AStr);
while P < PEnd do 
begin
  if P^ = Source then
    P^ := Target;
  Inc(P);
end;
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676434
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Посмотрите на тесты (Код с низу) Переносы не имеют значения никакого.
Код: sql
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.
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:415
ReplaceCharByPChar   -> 00:00:420
TestMy               -> 00:00:411
Самый быстрый: 3     -> 00:00:411
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:413
ReplaceCharByPChar   -> 00:00:417
TestMy               -> 00:00:412
Самый быстрый: 3     -> 00:00:412
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:416
ReplaceCharByPChar   -> 00:00:414
TestMy               -> 00:00:412
Самый быстрый: 3     -> 00:00:412
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:420
ReplaceCharByPChar   -> 00:00:412
TestMy               -> 00:00:413
Самый быстрый: 2     -> 00:00:412
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:429
ReplaceCharByPChar   -> 00:00:411
TestMy               -> 00:00:411
Самый быстрый: 3     -> 00:00:411



Код: pascal
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.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TCommatFunc = function(s: string): string;

  TForm1 = class(TForm)
    btnCommaToPoint: TButton;
    mmo1: TMemo;
    mmo2: TMemo;
    btnFill: TButton;
    procedure btnCommaToPointClick(Sender: TObject);
    procedure btnFillClick(Sender: TObject);
  private
    function RunFunc(Func: TCommatFunc): TDateTime;

    procedure FillRandomText(const iFactor, iCharCount: Integer);
    { Private declarations }
  public
    { Public declarations }
  end;

const
  CNT_RUN = 1000000;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function ForkReplaceC_lodsw(s: string): string;
const
  COMMA_ = ',';
  DOT_ = '.';
begin
  Result := s;

  asm
    Push  ESI
    Push  EBX

    Mov   EAX,Result
    Or    EAX,EAX
    Jz    @Exit
    Mov   ESI,[EAX]
    Or    ESI,ESI
    Jz    @Exit

    Mov   BH,COMMA_
    Mov   BL,DOT_
    Cmp   AH,BL
    Jz    @Exit

    Mov   ECX,[ESI-4]
    Jecxz @Exit
    push ECX

    shr ECX,1

    Cld
  @Next:
    Lodsw
    Cmp   AH,BH
    Jne   @Skip1
    Mov   [ESI-1],BL
  @Skip1:
    Cmp   AL,BH
    Jne   @Skip
    Mov   [ESI-2],BL
  @Skip:
    Dec   ECX
    Jnz   @Next

    // ------------------------
    pop ECX
    and ECX,2
    jz @Exit
  @Next20:
    Lodsb
    Cmp   AH,BH
    Jne   @Skip20
    Mov   [ESI-1],BL
  @Skip20:
    Dec   ECX
    Jnz   @Next20
  @Exit:
    Pop  EBX
    Pop  ESI

  end;
end;

function ReplaceCharByPChar(const s: string): string;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: PChar;
  i: Integer;
begin
  Result := s;
  P := Pointer(Result);
  for i := 0 to Length(s) - 1 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

function TestMy(const s: string): string;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: PChar;
begin
  Result := s;
  P := Pointer(Result);
  while P^ <> #0 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

var
  MinTest: TDateTime;
  IdxMin, IdxCurr: Integer;

procedure TForm1.btnCommaToPointClick(Sender: TObject);

  function FormatOutput(const aFuncName: string;
    const iRunTime: TDateTime): string;
  begin
    Result := Format('%-20s -> %s', [aFuncName, FormatDateTime('NN:SS:ZZZ',
      iRunTime)]);
  end;

begin
  MinTest := TDateTime(1000000000);
  IdxMin := 0;
  IdxCurr := 0;

  mmo1.Lines.Add('------------------------------------------------------');

  mmo1.Lines.Add(FormatOutput('ForkReplaceC_lodsw',
    RunFunc(@ForkReplaceC_lodsw)));

  mmo1.Lines.Add(FormatOutput('ReplaceCharByPChar',
    RunFunc(@ReplaceCharByPChar)));

  mmo1.Lines.Add(FormatOutput('TestMy', RunFunc(@TestMy)));

  mmo1.Lines.Add(FormatOutput('Самый быстрый: ' + (IdxMin + 1).ToString,
    MinTest));

end;

function TForm1.RunFunc(Func: TCommatFunc): TDateTime;
var
  aStartTime: TDateTime;
  i: Integer;
  s: string;
begin
  s := mmo2.Text;

  aStartTime := Now;

  for i := 0 to 50000 - 1 do
    Func(s);

  Result := Now - aStartTime;

  if MinTest - Result > 0 then
  begin
    MinTest := Result;
    IdxMin := IdxCurr;
  end;
  Inc(IdxCurr);
end;

procedure TForm1.FillRandomText(const iFactor, iCharCount: Integer);
var
  i: Integer;
  s: string;
begin
  s := '';

  for i := 0 to iCharCount do
  begin
    if Random(10) > iFactor then
      s := s + ','
    else
      s := s + Chr(40 + Trunc(Random(150)));
  end;

  mmo2.Text := s;

end;

procedure TForm1.btnFillClick(Sender: TObject);
begin
  FillRandomText(20, 10000);
end;

end.

...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676436
чччД__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
zinpub,

если строки ансишные, то табличку перекодировки сделай, должно весьма быстро получиться.


Код: pascal
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.
type
  TaRecode = array[Char] of Char;

var
  fRecode: TaRecode;

procedure Init();
var
  c: Char;
begin
  for c := Low(Char) to High(Char) do
    fRecode[c] := c;
  fRecode[','] := '.';
end;

procedure Recode(var str: string; const aRecode : TaRecode);
var
  i: Integer;
begin
  for i := 1 to Length(str) do
    str[i] := aRecode[str[i]];
end;
...
// Использование:
var
  fStr: string;
begin
  Init();
...
  fStr := '123,54';
  Recode(fStr, fRecode);
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676444
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чччД__,

Вообще ужассно

Код: sql
1.
2.
3.
4.
5.
6.
7.
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:435
ReplaceCharByPChar   -> 00:00:415
TestMy               -> 00:00:411
PEnd                 -> 00:00:411
Recode               -> 00:02:297
Самый быстрый: 3     -> 00:00:411



Код: pascal
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.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  ApChar = AnsiChar;
  ApString = AnsiString;
  ApPChar = PAnsiChar;

  TCommatFunc = function(s: ApString): ApString;

  TForm1 = class(TForm)
    btnCommaToPoint: TButton;
    mmo1: TMemo;
    mmo2: TMemo;
    btnFill: TButton;
    procedure btnCommaToPointClick(Sender: TObject);
    procedure btnFillClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    function RunFunc(Func: TCommatFunc): TDateTime;

    procedure FillRandomText(const iFactor, iCharCount: Integer);
    { Private declarations }
  public
    { Public declarations }
  end;

const
  CNT_RUN = 1000000;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function ForkReplaceC_lodsw(s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
begin
  Result := s;

  asm
    Push  ESI
    Push  EBX

    Mov   EAX,Result
    Or    EAX,EAX
    Jz    @Exit
    Mov   ESI,[EAX]
    Or    ESI,ESI
    Jz    @Exit

    Mov   BH,COMMA_
    Mov   BL,DOT_
    Cmp   AH,BL
    Jz    @Exit

    Mov   ECX,[ESI-4]
    Jecxz @Exit
    push ECX

    shr ECX,1

    Cld
  @Next:
    Lodsw
    Cmp   AH,BH
    Jne   @Skip1
    Mov   [ESI-1],BL
  @Skip1:
    Cmp   AL,BH
    Jne   @Skip
    Mov   [ESI-2],BL
  @Skip:
    Dec   ECX
    Jnz   @Next

    // ------------------------
    pop ECX
    and ECX,2
    jz @Exit
  @Next20:
    Lodsb
    Cmp   AH,BH
    Jne   @Skip20
    Mov   [ESI-1],BL
  @Skip20:
    Dec   ECX
    Jnz   @Next20
  @Exit:
    Pop  EBX
    Pop  ESI

  end;
end;

function ReplaceCharByPChar(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
  i: Integer;
begin
  Result := s;
  P := Pointer(Result);
  for i := 0 to Length(s) - 1 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

function TestMy(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
begin
  Result := s;
  P := Pointer(Result);
  while P^ <> #0 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

function PEnd(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
  PEnd: Pointer;
begin
  Result := s;
  P := Pointer(Result);
  PEnd := P + Length(s);
  while P < PEnd do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

type
  TaRecode = array [ApChar] of ApChar;

var
  fRecode: TaRecode;

procedure Init();
var
  c: ApChar;
begin
  for c := Low(ApChar) to High(ApChar) do
    fRecode[c] := c;
  fRecode[','] := '.';
end;

function Recode(str: ApString): ApString;
var
  i: Integer;
begin
  Result := str;
  for i := 1 to Length(Result) do
    Result[i] := fRecode[Result[i]];
end;

var
  MinTest: TDateTime;
  IdxMin, IdxCurr: Integer;

procedure TForm1.btnCommaToPointClick(Sender: TObject);

  function FormatOutput(const aFuncName: ApString; const iRunTime: TDateTime)
    : ApString;
  begin
    Result := Format('%-20s -> %s', [aFuncName, FormatDateTime('NN:SS:ZZZ',
      iRunTime)]);
  end;

begin
  MinTest := TDateTime(1000000000);
  IdxMin := 0;
  IdxCurr := 0;

  mmo1.Lines.Add('------------------------------------------------------');

  mmo1.Lines.Add(FormatOutput('ForkReplaceC_lodsw',
    RunFunc(@ForkReplaceC_lodsw)));

  mmo1.Lines.Add(FormatOutput('ReplaceCharByPChar',
    RunFunc(@ReplaceCharByPChar)));

  mmo1.Lines.Add(FormatOutput('TestMy', RunFunc(@TestMy)));

  mmo1.Lines.Add(FormatOutput('PEnd', RunFunc(@PEnd)));
  mmo1.Lines.Add(FormatOutput('Recode', RunFunc(@Recode)));

  mmo1.Lines.Add(FormatOutput('Самый быстрый: ' + (IdxMin + 1).ToString,
    MinTest));

end;

function TForm1.RunFunc(Func: TCommatFunc): TDateTime;
var
  aStartTime: TDateTime;
  i: Integer;
  s: ApString;
begin
  s := mmo2.Text;

  aStartTime := Now;

  for i := 0 to 50000 - 1 do
    Func(s);

  Result := Now - aStartTime;

  if MinTest - Result > 0 then
  begin
    MinTest := Result;
    IdxMin := IdxCurr;
  end;
  Inc(IdxCurr);
end;

procedure TForm1.FillRandomText(const iFactor, iCharCount: Integer);
var
  i: Integer;
  s: ApString;
begin
  s := '';

  for i := 0 to iCharCount do
  begin
    if Random(10) > iFactor then
      s := s + ','
    else
      s := s + Chr(40 + Trunc(Random(150)));
  end;

  mmo2.Text := s;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Init();
end;

procedure TForm1.btnFillClick(Sender: TObject);
begin
  FillRandomText(20, 10000);
end;

end.

...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676448
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И чего вам эти попугаи покоя не дают ? Или это возвращение великого оптимизатора ?
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676451
чччД__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ГирлионайльдоВообще ужассно
Да,, операция записи недешева.
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676453
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schiИ чего вам эти попугаи покоя не дают ? Или это возвращение великого оптимизатора ?

Самый оптимальный вариант. Быстрее только включить выравнивание на 16. И с помощью SSE инструкций искать маску символа. Прирост в два раза.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
function PEnd(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
  PEnd: Pointer;
begin
  Result := s;
  P := Pointer(Result);
  PEnd := P + Length(s);
  while P < PEnd do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676487
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоschiИ чего вам эти попугаи покоя не дают ? Или это возвращение великого оптимизатора ?

Самый оптимальный вариант. Быстрее только включить выравнивание на 16. И с помощью SSE инструкций искать маску символа. Прирост в два раза.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
function PEnd(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
  PEnd: Pointer;
begin
  Result := s;
  P := Pointer(Result);
  PEnd := P + Length(s);
  while P < PEnd do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;



Самый оптимальный вариант - это StringReplace. Дешево, сердито и всем понятно
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676507
чччД__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ГирлионайльдоВообще ужассно

А все символы в исходной строке требуют замену - что быстрее?

А если в множестве заменяемых символов больше одного элемента?
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676509
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schi
Самый оптимальный вариант - это StringReplace. Дешево, сердито и всем понятно

Он сначала выделяет 32 элемента в массив, и ищет через pos позиции, записывая их в массив. выделяя его, если нужно.
А потом только, он гуляет по этому массиву, и заменяет в строке нужные позиции


Короткий аналог, без массива

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
function ReplPos(const s: string): string;
label ToDo;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: PChar;
  FoundPos: Integer;
begin
  FoundPos := 1;
  Result := s;
ToDo:
  FoundPos := Pos(COMMA_, Result, FoundPos);
  if FoundPos = 0 then
    Exit;

  Result[FoundPos] := DOT_;
  Inc(FoundPos, 1);
  goto ToDo;
end;
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676513
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоСамый оптимальный вариант
А ничего, что в этом варианте есть сайд эффект - замена символов в исходной строке?
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676518
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чччД__, если массово заменять. То StringReplace проигрывает, а твоя функция по прежнему выдаёт тоже самое

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:410
ReplaceCharByPChar   -> 00:00:406
TestMy               -> 00:00:406
PEnd                 -> 00:00:407
StringReplace        -> 00:07:924
Recode               -> 00:02:484
Самый быстрый: 2     -> 00:00:406
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:410
ReplaceCharByPChar   -> 00:00:405
TestMy               -> 00:00:406
PEnd                 -> 00:00:404
StringReplace        -> 00:07:809
Recode               -> 00:02:480
Самый быстрый: 4     -> 00:00:404
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:411
ReplaceCharByPChar   -> 00:00:407
TestMy               -> 00:00:405
PEnd                 -> 00:00:407
StringReplace        -> 00:07:817
Recode               -> 00:02:484
Самый быстрый: 3     -> 00:00:405



код
Код: pascal
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.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  ApChar = AnsiChar;
  ApString = AnsiString;
  ApPChar = PAnsiChar;

  TCommatFunc = function(s: ApString): ApString;

  TForm1 = class(TForm)
    btnCommaToPoint: TButton;
    mmo1: TMemo;
    mmo2: TMemo;
    btnFill: TButton;
    Memo1: TMemo;
    procedure btnCommaToPointClick(Sender: TObject);
    procedure btnFillClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    function RunFunc(Func: TCommatFunc): TDateTime;

    procedure FillRandomText(const iFactor, iCharCount: Integer);
    { Private declarations }
  public
    { Public declarations }
  end;

const
  CNT_RUN = 1000000;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function ForkReplaceC_lodsw(s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
begin
  Result := s;

  asm
    Push  ESI
    Push  EBX

    Mov   EAX,Result
    Or    EAX,EAX
    Jz    @Exit
    Mov   ESI,[EAX]
    Or    ESI,ESI
    Jz    @Exit

    Mov   BH,COMMA_
    Mov   BL,DOT_
    Cmp   AH,BL
    Jz    @Exit

    Mov   ECX,[ESI-4]
    Jecxz @Exit
    push ECX

    shr ECX,1

    Cld
  @Next:
    Lodsw
    Cmp   AH,BH
    Jne   @Skip1
    Mov   [ESI-1],BL
  @Skip1:
    Cmp   AL,BH
    Jne   @Skip
    Mov   [ESI-2],BL
  @Skip:
    Dec   ECX
    Jnz   @Next

    // ------------------------
    pop ECX
    and ECX,2
    jz @Exit
  @Next20:
    Lodsb
    Cmp   AH,BH
    Jne   @Skip20
    Mov   [ESI-1],BL
  @Skip20:
    Dec   ECX
    Jnz   @Next20
  @Exit:
    Pop  EBX
    Pop  ESI

  end;
end;

function ReplaceCharByPChar(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
  i: Integer;
begin
  Result := s;
  P := Pointer(Result);
  for i := 0 to Length(s) - 1 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

function TestMy(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
begin
  Result := s;
  P := Pointer(Result);
  while P^ <> #0 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

function PEnd(const s: ApString): ApString;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: ApPChar;
  PEnd: Pointer;
begin
  Result := s;
  P := Pointer(Result);
  PEnd := P + Length(s);
  while P < PEnd do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

type
  TaRecode = array [ApChar] of ApChar;

var
  fRecode: TaRecode;

procedure Init();
var
  c: ApChar;
begin
  for c := Low(ApChar) to High(ApChar) do
    fRecode[c] := c;
  fRecode[','] := '.';
end;

function Recode(str: ApString): ApString;
var
  i: Integer;
begin
  Result := str;
  for i := 1 to Length(Result) do
    Result[i] := fRecode[Result[i]];
end;

function StrReplace(s: ApString): ApString;
begin
  Result := StringReplace(s, ',', '.', [rfReplaceAll]);

end;

var
  MinTest: TDateTime;
  IdxMin, IdxCurr: Integer;

procedure TForm1.btnCommaToPointClick(Sender: TObject);

  function FormatOutput(const aFuncName: ApString; const iRunTime: TDateTime)
    : ApString;
  begin
    Result := Format('%-20s -> %s', [aFuncName, FormatDateTime('NN:SS:ZZZ',
      iRunTime)]);
  end;

begin
  MinTest := TDateTime(1000000000);
  IdxMin := 0;
  IdxCurr := 0;

  mmo1.Lines.Add('------------------------------------------------------');

  mmo1.Lines.Add(FormatOutput('ForkReplaceC_lodsw',
    RunFunc(@ForkReplaceC_lodsw)));

  mmo1.Lines.Add(FormatOutput('ReplaceCharByPChar',
    RunFunc(@ReplaceCharByPChar)));

  mmo1.Lines.Add(FormatOutput('TestMy', RunFunc(@TestMy)));

  mmo1.Lines.Add(FormatOutput('PEnd', RunFunc(@PEnd)));

  mmo1.Lines.Add(FormatOutput('StringReplace', RunFunc(@StrReplace)));

  mmo1.Lines.Add(FormatOutput('Recode', RunFunc(@Recode)));

  mmo1.Lines.Add(FormatOutput('Самый быстрый: ' + (IdxMin + 1).ToString,
    MinTest));

end;

function TForm1.RunFunc(Func: TCommatFunc): TDateTime;
var
  aStartTime: TDateTime;
  i: Integer;
  s: ApString;
begin
  s := mmo2.Text;

  aStartTime := Now;

  for i := 0 to 50000 - 1 do
    Func(s);

  Result := Now - aStartTime;

  if MinTest - Result > 0 then
  begin
    MinTest := Result;
    IdxMin := IdxCurr;
  end;
  Inc(IdxCurr);
end;

procedure TForm1.FillRandomText(const iFactor, iCharCount: Integer);
var
  i: Integer;
  s: ApString;
begin
  s := '';

  for i := 0 to iCharCount do
  begin
    s := s + ','
  end;

  mmo2.Text := s;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Init();
end;

procedure TForm1.btnFillClick(Sender: TObject);
begin
  FillRandomText(20, 10000);
end;

end.



Код: pascal
1.
2.
3.
4.
  for i := 0 to iCharCount do
  begin
    s := s + ','
  end;
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676519
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey,

мы двигаем 1 указатель, который в конце нигде не используется. Думаю что не вызовет порчу памяти
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676523
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гирлионайльдомы двигаем 1 указатель, который в конце нигде не используется. Думаю что не вызовет порчу памяти
Я о том, что у тебя содержимое const s: string; меняется.
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676525
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey,

не доглядел)
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676528
haydegen
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676530
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гирлионайльдоне доглядел)
Ещё, если хочешь ускориться обрабатывай по несколько символов за итерацию.
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676531
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоschiСамый оптимальный вариант - это StringReplace. Дешево, сердито и всем понятно

Он сначала выделяет 32 элемента в массив, и ищет через pos позиции, записывая их в массив. выделяя его, если нужно.
А потом только, он гуляет по этому массиву, и заменяет в строке нужные позиции


Короткий аналог, без массива

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
function ReplPos(const s: string): string;
label ToDo;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: PChar;
  FoundPos: Integer;
begin
  FoundPos := 1;
  Result := s;
ToDo:
  FoundPos := Pos(COMMA_, Result, FoundPos);
  if FoundPos = 0 then
    Exit;

  Result[FoundPos] := DOT_;
  Inc(FoundPos, 1);
  goto ToDo;
end;



"Я понимаю, лет 30-40 назад, при тогдашней стоимости и производительности железа имело смысл минимизировать все и везде, вплоть до оптимизации кода инициализации. Но сейчас смысла в этих попытках столько же, сколько в тщательном измерении длины шага мерина, которого ведут на живодерню (с) Виктор Конецкий

Мне без разницы, занимает утилита 12 килобайт или 10 мебагайт, если она делает то, что мне нужно. "
20472449
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676542
zinpub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
schiИ чего вам эти попугаи покоя не дают ? Или это возвращение великого оптимизатора ?

Неет, мне хватает варианта by Vassily2, но ради интереса...
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676543
zinpub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ГирлионайльдоПосмотрите на тесты (Код с низу) Переносы не имеют значения никакого.
Код: sql
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.
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:415
ReplaceCharByPChar   -> 00:00:420
TestMy               -> 00:00:411
Самый быстрый: 3     -> 00:00:411
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:413
ReplaceCharByPChar   -> 00:00:417
TestMy               -> 00:00:412
Самый быстрый: 3     -> 00:00:412
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:416
ReplaceCharByPChar   -> 00:00:414
TestMy               -> 00:00:412
Самый быстрый: 3     -> 00:00:412
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:420
ReplaceCharByPChar   -> 00:00:412
TestMy               -> 00:00:413
Самый быстрый: 2     -> 00:00:412
------------------------------------------------------
ForkReplaceC_lodsw   -> 00:00:429
ReplaceCharByPChar   -> 00:00:411
TestMy               -> 00:00:411
Самый быстрый: 3     -> 00:00:411



Код: pascal
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.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TCommatFunc = function(s: string): string;

  TForm1 = class(TForm)
    btnCommaToPoint: TButton;
    mmo1: TMemo;
    mmo2: TMemo;
    btnFill: TButton;
    procedure btnCommaToPointClick(Sender: TObject);
    procedure btnFillClick(Sender: TObject);
  private
    function RunFunc(Func: TCommatFunc): TDateTime;

    procedure FillRandomText(const iFactor, iCharCount: Integer);
    { Private declarations }
  public
    { Public declarations }
  end;

const
  CNT_RUN = 1000000;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function ForkReplaceC_lodsw(s: string): string;
const
  COMMA_ = ',';
  DOT_ = '.';
begin
  Result := s;

  asm
    Push  ESI
    Push  EBX

    Mov   EAX,Result
    Or    EAX,EAX
    Jz    @Exit
    Mov   ESI,[EAX]
    Or    ESI,ESI
    Jz    @Exit

    Mov   BH,COMMA_
    Mov   BL,DOT_
    Cmp   AH,BL
    Jz    @Exit

    Mov   ECX,[ESI-4]
    Jecxz @Exit
    push ECX

    shr ECX,1

    Cld
  @Next:
    Lodsw
    Cmp   AH,BH
    Jne   @Skip1
    Mov   [ESI-1],BL
  @Skip1:
    Cmp   AL,BH
    Jne   @Skip
    Mov   [ESI-2],BL
  @Skip:
    Dec   ECX
    Jnz   @Next

    // ------------------------
    pop ECX
    and ECX,2
    jz @Exit
  @Next20:
    Lodsb
    Cmp   AH,BH
    Jne   @Skip20
    Mov   [ESI-1],BL
  @Skip20:
    Dec   ECX
    Jnz   @Next20
  @Exit:
    Pop  EBX
    Pop  ESI

  end;
end;

function ReplaceCharByPChar(const s: string): string;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: PChar;
  i: Integer;
begin
  Result := s;
  P := Pointer(Result);
  for i := 0 to Length(s) - 1 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

function TestMy(const s: string): string;
const
  COMMA_ = ',';
  DOT_ = '.';
var
  P: PChar;
begin
  Result := s;
  P := Pointer(Result);
  while P^ <> #0 do
  begin
    if P^ = COMMA_ then
      P^ := DOT_;
    Inc(P);
  end;
end;

var
  MinTest: TDateTime;
  IdxMin, IdxCurr: Integer;

procedure TForm1.btnCommaToPointClick(Sender: TObject);

  function FormatOutput(const aFuncName: string;
    const iRunTime: TDateTime): string;
  begin
    Result := Format('%-20s -> %s', [aFuncName, FormatDateTime('NN:SS:ZZZ',
      iRunTime)]);
  end;

begin
  MinTest := TDateTime(1000000000);
  IdxMin := 0;
  IdxCurr := 0;

  mmo1.Lines.Add('------------------------------------------------------');

  mmo1.Lines.Add(FormatOutput('ForkReplaceC_lodsw',
    RunFunc(@ForkReplaceC_lodsw)));

  mmo1.Lines.Add(FormatOutput('ReplaceCharByPChar',
    RunFunc(@ReplaceCharByPChar)));

  mmo1.Lines.Add(FormatOutput('TestMy', RunFunc(@TestMy)));

  mmo1.Lines.Add(FormatOutput('Самый быстрый: ' + (IdxMin + 1).ToString,
    MinTest));

end;

function TForm1.RunFunc(Func: TCommatFunc): TDateTime;
var
  aStartTime: TDateTime;
  i: Integer;
  s: string;
begin
  s := mmo2.Text;

  aStartTime := Now;

  for i := 0 to 50000 - 1 do
    Func(s);

  Result := Now - aStartTime;

  if MinTest - Result > 0 then
  begin
    MinTest := Result;
    IdxMin := IdxCurr;
  end;
  Inc(IdxCurr);
end;

procedure TForm1.FillRandomText(const iFactor, iCharCount: Integer);
var
  i: Integer;
  s: string;
begin
  s := '';

  for i := 0 to iCharCount do
  begin
    if Random(10) > iFactor then
      s := s + ','
    else
      s := s + Chr(40 + Trunc(Random(150)));
  end;

  mmo2.Text := s;

end;

procedure TForm1.btnFillClick(Sender: TObject);
begin
  FillRandomText(20, 10000);
end;

end.



Не переносы, а запятые, которые и надо заменять
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676545
zinpub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
чччД__ГирлионайльдоВообще ужассно

А все символы в исходной строке требуют замену - что быстрее?

А если в множестве заменяемых символов больше одного элемента?

Строка от 120 до 370 символов. Запятых от 12 до 67
...
Рейтинг: 0 / 0
Быстрая замена символа
    #39676546
zinpub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
haydegenГирлионайльдо, добавь https://bitbucket.org/alex7691/delphi/src/master/FastStringReplace/

Оттуда и брал начальный вариант 😔
...
Рейтинг: 0 / 0
25 сообщений из 259, страница 2 из 11
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Быстрая замена символа
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]