Быстрое дополнение строки в Delphi

У меня была эта та же проблема на Ubuntu 8.10 с Ganymede и Tomcat6. Это, кажется, своего рода ошибка с Eclipse. При попытке создать сервер, и он блюет, Вы не можете создать другой tomcat6 сервер. Для исправления этой проблемы сделайте следующее:

  • близкое затмение
  • переходит в {каталог рабочей области}/.metadata/.plugins/org.eclipse.core.runtime/.settings каталог и удаляет файл, названный org.eclipse.wst.server.core.prefs.
  • запускаются, затмение
  • добавляют Ваш tomcat6 сервер на вкладке

kotfu

сервера
11
задан Svein Bringsli 5 November 2009 в 09:28
поделиться

7 ответов

Ваша новая функция включает в себя три строки: вход, результат из StringOfChar и результат функции. Один из них уничтожается, когда ваша функция возвращается. Вы можете сделать это за два, и ничего не будет разрушено или перераспределено.

  1. Выделите строку полной требуемой длины.
  2. Заполните первую ее часть своим символом заполнения.
  3. Заполните остальную часть. со входной строкой.

Вот пример:

function cwLeftPad(const aString: AnsiString; aCharCount: Integer; aChar: AnsiChar): AnsiString;
var
  PadCount: Integer;
begin
  PadCount := ACharCount - Length(AString);
  if PadCount > 0 then begin
    SetLength(Result, ACharCount);
    FillChar(Result[1], PadCount, AChar);
    Move(AString[1], Result[PadCount + 1], Length(AString));
  end else
    Result := AString;
end;

Я не знаю, предоставляют ли Delphi 2009 и более поздние версии двухбайтовый эквивалент FillChar на основе Char, и если они это сделают, я не знаю, как это называется , поэтому я изменил подпись функции, чтобы явно использовать AnsiString. Если вам нужна WideString или UnicodeString, вам нужно будет найти замену FillChar, которая обрабатывает двухбайтовые символы. (FillChar имеет сбивающее с толку имя в Delphi 2009, так как он не обрабатывает полноразмерные значения Char.)

Еще одна вещь, которую следует учитывать, - действительно ли вам вообще нужно вызывать эту функцию так часто. Самый быстрый код - это код, который никогда не запускается.

12
ответ дан 3 December 2019 в 03:18
поделиться

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

function cwLeftPad(aString:string; aCharCount:integer; aChar:char): string;
var
  i,vLength:integer;
  origSize: integer;
begin
  Result := aString;
  origSize := Length(Result);
  if aCharCount <= origSize then
    Exit;
  SetLength(Result, aCharCount);
  Move(Result[1], Result[aCharCount-origSize+1], origSize * SizeOf(char));
  for i := 1 to aCharCount - origSize do
    Result[i] := aChar;
end;

РЕДАКТИРОВАТЬ: Я провел некоторое тестирование, и моя функция работает медленнее, чем ваш улучшенный cwLeftPad. Но я нашел кое-что еще - вашему процессору не требуется 5 секунд для выполнения 35k функций cwLeftPad, кроме случаев, когда вы работаете на PC XT или форматируете гигабайтные строки.

Я тестировал этот простой код

for i := 1 to 35000 do begin
  a := 'abcd1234';
  b := cwLeftPad(a, 73, '.');
end;

и получил 255 миллисекунд для вашего исходного cwLeftPad, 8 миллисекунд для вашего улучшенного cwLeftPad и 16 миллисекунд для моей версии.

4
ответ дан 3 December 2019 в 03:18
поделиться

Еще одна мысль - если это Delphi 2009 или 2010, отключите «Проверку формата строки» в Project, Options, Delphi Compiler, Compiling, Code Generation.

6
ответ дан 3 December 2019 в 03:18
поделиться

Вы можете еще больше ускорить эту процедуру, используя поисковый массив.

Конечно, это зависит от ваших требований. Если вы не против потратить немного памяти ... Я предполагаю, что функция вызывается 35 k раз, но у нее нет 35000 различной длины заполнения и множества разных символов.

Итак, если вы знаете (или можете быстро оценить) диапазон отступов и символов заполнения вы можете построить двумерный массив, включающий эти параметры. Для простоты я предполагаю, что у вас есть 10 различных длин заполнения, и вы заполняете его одним символом - '.', Поэтому в примере это будет одномерный массив.

Вы реализуете это следующим образом:

type
  TPaddingArray = array of String;

var
  PaddingArray: TPaddingArray;
  TestString: String;

function cwLeftPad4(const aString:string; const aCharCount:integer; const aChar:char; var anArray: TPaddingArray ): string;
begin
  Result := anArray[aCharCount-length(aString)] + aString;
end;

begin
  //fill up the array
  SetLength(StrArray, 10);
  PaddingArray[0] := '';
  PaddingArray[1] := '.';
  PaddingArray[2] := '..';
  PaddingArray[3] := '...';
  PaddingArray[4] := '....';
  PaddingArray[5] := '.....';
  PaddingArray[6] := '......';
  PaddingArray[7] := '.......';
  PaddingArray[8] := '........';
  PaddingArray[9] := '.........';

  //and you call it..
  TestString := cwLeftPad4('Some string', 20, '.', PaddingArray);
end;

Здесь результаты тестов:

Time1 - oryginal cwLeftPad          : 27,0043604142394 ms.
Time2 - your modyfication cwLeftPad : 9,25971967336897 ms.
Time3 - Rob Kennedy's version       : 7,64538131122457 ms.
Time4 - cwLeftPad4                  : 6,6417059620664 ms.

Обновленные тесты:

Time1 - oryginal cwLeftPad          : 26,8360194218451 ms.
Time2 - your modyfication cwLeftPad : 9,69653117046119 ms.
Time3 - Rob Kennedy's version       : 7,71149259179622 ms.
Time4 - cwLeftPad4                  : 6,58248533610693 ms.
Time5 - JosephStyons's version      : 8,76641780969192 ms.

Вопрос: стоит ли это хлопот?; -)

2
ответ дан 3 December 2019 в 03:18
поделиться

Теперь вы каждый раз вызываете StringOfChar. Конечно, этот метод проверяет, есть ли у него что-то делать, и выскакивает, если длина достаточно мала, но, возможно, вызов StringOfChar занимает много времени, потому что внутри он выполняет еще один вызов перед тем, как выпрыгнуть.

Так что моей первой идеей было бы выпрыгиваю один, если нечего делать:

function cwLeftPad(const aString: string; aCharCount: Integer; aChar: Char;): string;
var
  l_restLength: Integer;
begin
  Result  := aString;
  l_restLength := aCharCount - Length(aString);
  if (l_restLength < 1) then
    exit;

  Result := StringOfChar(aChar, l_restLength) + aString;
end;
2
ответ дан 3 December 2019 в 03:18
поделиться

Возможно, будет быстрее использовать StringOfChar для выделения совершенно новой строки длиной строки и заполнения, а затем использовать move, чтобы скопировать существующий текст поверх нее.
Я думаю, что вы создаете две новые строки выше (одну с FillChar и одну с плюсом). Для этого требуются два выделения памяти и конструкции строкового псевдообъекта. Это будет медленно. Может быть быстрее потратить несколько циклов ЦП на избыточное заполнение, чтобы избежать дополнительных операций с памятью.
Это может быть даже быстрее, если вы выделили пространство памяти, а затем выполнили FillChar и Move, но дополнительный вызов fn может замедлить это.
Часто это делается методом проб и ошибок!

1
ответ дан 3 December 2019 в 03:18
поделиться

Вы можете значительно повысить производительность, если заранее выделите строку.

function cwLeftPadMine
{$IFDEF VER210}  //delphi 2010
(aString: ansistring; aCharCount: integer; aChar: ansichar): ansistring;
{$ELSE}
(aString: string; aCharCount: integer; aChar: char): string;
{$ENDIF}
var
  i,n,padCount: integer;
begin
  padCount := aCharCount - Length(aString);

  if padCount > 0 then begin
    //go ahead and set Result to what it's final length will be
    SetLength(Result,aCharCount);
    //pre-fill with our pad character
    FillChar(Result[1],aCharCount,aChar);

    //begin after the padding should stop, and restore the original to the end
    n := 1;
    for i := padCount+1 to aCharCount do begin
      Result[i] := aString[n];
    end;
  end
  else begin
    Result := aString;
  end;
end;

А вот шаблон, который является полезно для сравнения:

procedure TForm1.btnPadTestClick(Sender: TObject);
const
  c_EvalCount = 5000;  //how many times will we run the test?
  c_PadHowMany = 1000;  //how many characters will we pad
  c_PadChar = 'x';  //what is our pad character?
var
  startTime, endTime, freq: Int64;
  i: integer;
  secondsTaken: double;
  padIt: string;
begin
  //store the input locally
  padIt := edtPadInput.Text;

  //display the results on the screen for reference
  //(but we aren't testing performance, yet)
  edtPadOutput.Text := cwLeftPad(padIt,c_PadHowMany,c_PadChar);

  //get the frequency interval of the OS timer    
  QueryPerformanceFrequency(freq);

  //get the time before our test begins
  QueryPerformanceCounter(startTime);

  //repeat the test as many times as we like
  for i := 0 to c_EvalCount - 1 do begin
    cwLeftPad(padIt,c_PadHowMany,c_PadChar);
  end;

  //get the time after the tests are done
  QueryPerformanceCounter(endTime);

  //translate internal time to # of seconds and display evals / second
  secondsTaken := (endTime - startTime) / freq;
  if secondsTaken > 0 then begin
    ShowMessage('Eval/sec = ' + FormatFloat('#,###,###,###,##0',
      (c_EvalCount/secondsTaken)));
  end
  else begin
    ShowMessage('No time has passed');
  end;
end;

Используя этот шаблон теста, я получил следующие результаты:

The original: 5,000 / second
Your first revision: 2.4 million / second
My version: 3.9 million / second
Rob Kennedy's version: 3.9 million / second
1
ответ дан 3 December 2019 в 03:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: