Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.02.2024, 01:48   #1
Kronos913
Форумчанин
 
Регистрация: 10.02.2021
Сообщений: 637
По умолчанию Строка из подстроки (тест BASM-функции)

После кучи доработок, функция прошла тесты, но может я что-то не заметил, потому просьба помочь с тестами. Да и просто, может я не совсем верно что-то написал и что-то можно было сделать проще

Итак, что за функция.
К примеру у меня есть строка '000.111.222.333.444'
Функция из нее должна извлечь определенный фрагмент между точками и вернуть во вторую строку

Третий параметр. чтобы при вызове функции не дёргать стек, сразу три параметра были склеены в один LongWord

4 байт - номер необходимой подстроки начиная с 0
3 байт - код чара-разделителя
1-2 байты - это если эта функция используется в цикле, чтобы каждый раз не дёргать функцию Length, длину можно один раз найти и передавать в 1-2 байтах

Результат функции должен давать false если пустая входящая строка, или если запрашивается подстрока которой нет (запросили подстроку номер 5, а их всего 3)

Код:
Function PartString(const MainStrIn:string; var StrOut:string; const Len12_Char3_Number4:LongWord):boolean; register
asm
  push edi
  push esi
  push ebx

  mov edi, MainStrIn
  mov esi, StrOut
  mov ebx, Len12_Char3_Number4
  {Сохраняем все введенные данные для того чтобы вызов другой функции их не испортил}

  {Проверяем задана ли длина изначально}
  cmp ebx, 65535
    ja @Dlina_1

  call system.@LStrLen
  jmp @DlinaEnd

  @Dlina_1:
  mov eax, ebx
  shr eax, 16

  @DlinaEnd: {Теперь у нас есть длина строки}

  cmp eax, 0 {Если длина = 0 то выходим}
    je @Exit1

  {eax - dlina, ebx - dannye, edi - StiIn, esi - StrOut}
  mov edx, edi
  add edx, eax
  {edx - предел}

  mov eax, edi {теперь eax будет рабочей ссылкой}

  mov ch, [eax]
  cmp ch, bh   {Проверяем не является ли первый символ - разделителем}
    jne @Begin1
  inc eax

  @Begin1:
    cmp bl, 0 {Когда счётчик дойдёт до нуля - то мы окажемся на начале нужного фрагмента}
      je  @End1

    @Point2:
    cmp eax, edx {Если мы вышли за предел - на выход}
      jae @ExitF

    mov ch, [eax]
    inc eax {Сразу смещаемся на следующий символ}

    cmp ch, bh {Проверяем не разделитель ли это}
      jne @Point2

    dec bl {Если разделитель - значит счетчик на 1 снижаем}
    jmp @Begin1
  @End1:

  push esi {Строка Out уже в стеке для вызова Copy}

  mov esi, eax  {Зафиксировали момент начала}
  inc esi {После тестов добавил это смещение на 1}

  @Begin3:
     cmp eax, edx {Проверяем доход до края}
       jae @End3

     mov ch, [eax]
     cmp ch, bh  {Проверяем доход до разделителя}
       je @End3

     inc eax     {Если не дошли - то сдвиг}
     jmp @Begin3
  @End3:

  mov ecx, eax
  sub ecx, esi {Задали количество}
  inc ecx {После тестов добавил это смещение на 1}

  mov edx, esi
  sub edx, edi {Задали номер начала}

  mov eax, edi {Вернули сюда ссыдку на начало}

  call system.@LStrCopy

  mov eax, 1 {Задали true функции}
  jmp @Exit1

  @ExitF:
  mov eax, 0

  @Exit1:
  pop ebx
  pop esi
  pop edi
end;
Kronos913 вне форума Ответить с цитированием
Старый 10.02.2024, 04:44   #2
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,314
По умолчанию

Ассемблер не проверял - лень думать. А в чем все-таки смысл опускаться до ассемблера, если небрежно написанная на дельфи функция (PartString2) работает соизмеримое время? А если предварительно "нарезать" строку, а потом только доставать подстроки, то и быстрее (PartString4).
Код:
Function PartString2(const MainStrIn: string; var StrOut: string; const Sep: Char; Number: Byte): boolean;
var
  len, i, start_pos, end_pos: integer;
begin
  result := False;
  len := Length(MainStrIn);
  if len = 0 then
    exit;
  start_pos := -1;
  end_pos := -1;
  if Number = 0 then
    start_pos := 1;
  for i := 1 to len do
    if MainStrIn[i] = Sep then
    begin
      Dec(Number);
      if Number = 0 then
        start_pos := i + 1
      else if Number = 255 then
      begin
        end_pos := i - 1;
        Break;
      end;
    end;
  if start_pos = -1 then
    exit;
  if end_pos = -1 then
    end_pos := len;
  StrOut := Copy(MainStrIn, start_pos, end_pos - start_pos + 1);
  result := True;
end;

Function PartString3(const MainStrIn: string; var StrOut: string; const Sep: Char; Number: Byte; ListOfStrings: TStrings): boolean;
begin
  result := False;
  ListOfStrings.Clear;
  ListOfStrings.Delimiter := Sep;
  ListOfStrings.DelimitedText := MainStrIn;
  if ListOfStrings.Count <= Number then
    exit;
  StrOut := ListOfStrings[Number];
  result := True;
end;

Function PartString4(var StrOut: string; Number: Byte; ListOfStrings: TStrings): boolean;
begin
  result := False;
  if ListOfStrings.Count <= Number then
    exit;
  StrOut := ListOfStrings[Number];
  result := True;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
  s, res1, res2, res3, res4: string;
  startTime64, endTime64, frequency64: Int64;
  elapsedSeconds1, elapsedSeconds2, elapsedSeconds3, elapsedSeconds4: single;
  i: integer;
  tmpList: TStringList;
begin
  s := '000.111.222.333.444';

  QueryPerformanceFrequency(frequency64);
  QueryPerformanceCounter(startTime64);
  for i := 1 to 1000000 do
    PartString(s, res1, Ord('.') shl 8 + 1);
  QueryPerformanceCounter(endTime64);
  elapsedSeconds1 := (endTime64 - startTime64) / frequency64;

  QueryPerformanceFrequency(frequency64);
  QueryPerformanceCounter(startTime64);
  for i := 1 to 1000000 do
    PartString2(s, res2, '.', 1);
  QueryPerformanceCounter(endTime64);
  elapsedSeconds2 := (endTime64 - startTime64) / frequency64;

  QueryPerformanceFrequency(frequency64);
  QueryPerformanceCounter(startTime64);
  tmpList := TStringList.Create;
  for i := 1 to 1000000 do
    PartString3(s, res3, '.', 1, tmpList);
  tmpList.Free;
  QueryPerformanceCounter(endTime64);
  elapsedSeconds3 := (endTime64 - startTime64) / frequency64;

  QueryPerformanceFrequency(frequency64);
  QueryPerformanceCounter(startTime64);
  tmpList := TStringList.Create;
  // prepare
  tmpList.Clear;
  tmpList.Delimiter := '.';
  tmpList.DelimitedText := s;
  for i := 1 to 1000000 do
    PartString4(res4, 1, tmpList);
  tmpList.Free;
  QueryPerformanceCounter(endTime64);
  elapsedSeconds4 := (endTime64 - startTime64) / frequency64;

  ShowMessage(
    '"' + res1 + '" ' + FloatToStr(elapsedSeconds1) + sLineBreak +
    '"' + res2 + '" ' + FloatToStr(elapsedSeconds2) + sLineBreak +
    '"' + res3 + '" ' + FloatToStr(elapsedSeconds3) + sLineBreak +
    '"' + res4 + '" ' + FloatToStr(elapsedSeconds4)
  );
end;
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )

Последний раз редактировалось BDA; 10.02.2024 в 04:47.
BDA на форуме Ответить с цитированием
Старый 10.02.2024, 12:33   #3
digitalis
Старожил
 
Аватар для digitalis
 
Регистрация: 04.02.2011
Сообщений: 4,555
По умолчанию

Важен сам процесс... "Цель - ничто, движение к цели - всё"
digitalis вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обратиться к регистру через методы delphi? Или вызов функции из basm Kronos913 Общие вопросы Delphi 2 22.04.2022 21:44
PHPunit тест для функции APlayer PHP 0 19.09.2017 11:58
Задана строка A(N). Вычислить для каждой подстроки функцию A(i), равную палиндрому максимальной длины forged Паскаль, Turbo Pascal, PascalABC.NET 3 24.12.2013 12:56
Строка из цифр и её подстроки(Pascal) MuruMec Помощь студентам 8 04.12.2013 19:06
PCHAR строка с разделителями #13#10. Как вычленить отдельные "подстроки" EdNovice Общие вопросы Delphi 1 17.04.2007 11:42