На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> function PreXMLFast
    Доброе время суток, уважаемые форумчане.)
    Нужно перевести функцию с delphi в delphi asm.
    Не силен в asm'e. :'( Спасибо. :thanks:

    ExpandedWrap disabled
      function PreXML(S: string): string;
      var i:integer;
      begin
      for I := 1 to Length(s) do
                if s[i] = #62 then insert(#13#10,s,i+1);
        Result:= S;
      end;

    :scratch:
    Сообщение отредактировано: RusSun -
      Скомпилируй программу, поставь брекпойнт на вызове функции, при останове переключись в просмотр сгенерированного asm-кода Alt-Ctrl-C
        Цитата RusSun @
        Нужно перевести функцию с delphi в delphi asm.

        А зачем?
        Можно последовать совету MBo и "содрать" asm-листинг функции из окна CPU. Вот только вопрос - зачем? Чем это будет лучше использования исходной функции на паскале (которая компилируется точно в такой же asm-код)?

        Проблема в том, что тут используется спец.встроенный тип данных string, причем не просто в режиме чтения, а в режиме наращивания длины функцией Insert, за которой на самом деле скрывается некая недокументированная "магическая" функция компилятора типа _UStrInsert (плюс еще пара аналогичных функций _UStrAddRef и _UStrAsg). Внимание, вопрос: зачем использовать асм-код с вызовом недокументированных магических функций, если компилятор сам сделает точно такой-же код из исходника функции PreXML, использующего нормальную документированную функцию Insert?

        Добавлено
        Подозреваю, что при обработке больших XML документов функция PreXML сильно тормозит, и ты наивно полагаешь, что если ее переписать на asm, то она будет работать "намного быстрее"?
        Это не верно. Тут весь тормоз в использовании функции Insert, которая во-первых, при каждой вставке вынуждена перемещать весь длинный хвост строки, во-вторых, через несколько вставок вынуждена увеличивать длину буфера строки (с вызовом ReallocMem - возможно с перемещением всей строки на другой адрес, если не удается увеличить размер буфера по тому же адресу).
        Поэтому для увеличения быстродействия нужно:
        1) Не изменять исходную строку, а выделить новую строку под Result и копировать в нее куски исходной строки между символами '>' и добавлять после них разделители #13#10. (При этом символы нужно искать ф-ей PosEx, а не обычной Pos).
        2) Для уменьшения кол-ва реаллокаций строки Result можно выделять память под нее (через SetLength) не точно на +2, а достаточно большими блоками (например по 256 байт). А в конце обработки урезать длину до реальной скопированной. (Также возможен вариант, когда за первый проход производится подсчет кол-ва символов '>', затем выделяется строка Result нужной длины, и за второй проход осуществляется копирование s в Result со вставкой разделителей).
        И никакой asm тут не нужен - и на паскале все будет работать намного быстрее.
        Сообщение отредактировано: leo -
          Могу предположить:
          а) учебная задача
          б) проблемы с быстродействием

          Во втором случае проблемы из-за неверно выбранного алгоритма обработки - многократное
          перераспределение памяти при изменении длины строки (думаю, оно будет и при замене функции более кратким аналогом Stringreplace)
          Его можно избежать, выделив новую строку с запасом и переписывая куски и добавки в неё.
            Кстати, мне не так давно пришлось конвертер формата XML-файлов росреестра (КПТ) слепить на коленке по аналогичному принципу. Работает вообще "мгновенно", по сравнению с "обычными поделками", которые "жуют сопли" по несколько минут :)
            (Если выходные данные должны записывать в файл, то размер выходного буфера лучше сразу брать не менее 1-2 Мб, и сбрасывать данные на диск при его "переполнении")
              Да, проблема с быстродействием. В какой-то степени, можно сказать, что учебная тоже.
              Пишу с телефона поэтому мне не совсем удобно.
              Дополнительно напишу вечером.
                А StringReplace() не быстрее?
                  ExpandedWrap disabled
                    Function PosEx(Const SubStr, S: String; Offset: Cardinal = 1): Integer;
                    var
                     I,X: Integer;
                     Len, LenSubStr: Integer;
                    begin
                     If Offset = 1 Then
                      Result := Pos(SubStr, S)
                     Else
                     begin
                      I := Offset;
                      LenSubStr := Length(SubStr);
                      Len := Length(S) - LenSubStr + 1;
                      While I <= Len Do
                      begin
                      If S[I] = SubStr[1] Then
                      begin
                      X := 1;
                      While (X < LenSubStr) And (S[I + X] = SubStr[X + 1]) Do
                      Inc(X);
                      If (X = LenSubStr) Then
                      begin
                      Result := I;
                      Exit;
                      End;
                      End;
                      Inc(I);
                      End;
                      Result := 0;
                     End;
                    End;
                     
                    function PreXMLFast(S: string): string;
                    var beforePos:integer;//позиция копирования
                        sPos:integer; //начальная позиция
                        str:string;
                        sResult:string;
                      begin
                        sPos:= 1;
                        str:= '';
                        sResult:= '';
                        beforePos:=1;
                    repeat
                    sPos:=PosEx('>',S,sPos);    //#62
                    if sPos<>0 then
                    begin
                    inc(sPos);
                    //str:= str +intTostr (beforePos) + ', '+intTostr (sPos) +' ; :' j; // найденные позиции
                    sResult:=sResult+Copy(S, beforePos ,sPos-beforePos)+#13#10;
                    beforePos:=sPos;
                    inc (sPos);
                    end;
                    until sPos=0; //вертим цикл пока sPos не станет равным О
                    //result;=str4#13#10+sResult:
                    result:=sResult;
                    end;


                  На работе испытывал следующие 2 файла.



                  “replace” from somewhere internetPreXMLPreXMLFastPreXmlFast"StrReplaceKOLPreXmlStringReplaceAll...
                  Test16019 строк634 kb3869 ms359 ms234 ms265 ms1123 ms4992-5023 ms ...
                  Test2119739 строк13,2 mb2235916 ms135253 ms4462 ms10873 ms27160 ms1786367 ms ...


                  можно еще быстрее? :scratch:
                  Сообщение отредактировано: RusSun -
                    Однобайтный=односимвольный вариант PosEx некачественно, но ускорит ещё несколько. :blush:

                    Добавлено
                    А ещё несколько ускорит (не сильно и мало!) прямое вписывание пары байт #13#10 в нужное в хвосте место, вместо ГОСТ'овской приписки к строке. Т.к. она (приписка) наверняка лишний раз посканирует строку для поиска конца, а это излишне. ;)
                      Цитата
                      А StringReplace() не быстрее?

                      Код процедуры. Чтобы сделать тест.Спасибо
                        RusSun
                        Я как понял ты ищешь #62 и если есть то вставляешь #13#10.
                        Так ты сделай замену #62 на #62#13#10 через StringReplace().

                        ExpandedWrap disabled
                          Result:=StringReplace(s,#62, #62#13#10,[rfReplaceAll, rfIgnoreCase]);


                        Какой ещё нужен код? :) :)
                          Цитата ^D^ima @
                          А StringReplace() не быстрее?

                          По сравнению с Insert быстрее, а по сравнению с PreXMLFast из #8 скорее всего медленнее. Например, в Delphi 7 точно медленнее, т.к. в ней используется не PosEx, а просто Pos (AnsiPos) и соотв-но после каждого поиска изменяется не только строка Result, но и строка поиска (обрезается спереди по найденному символу через ту же Copy).

                          PS: Тем более для символа #62 = '>' не имеет смысла использовать опцию rfIgnoreCase, которая лишь добавляет тормозов на преобразование регистра исходной строки.
                          Сообщение отредактировано: leo -
                            Цитата RusSun @
                            можно еще быстрее?

                            Можно (не знаю насколько).
                            Из советов в #3-4 ты реализовал только копирование символов из исходной строки в новую строку Result. Но тормоза за счет многократного наращивания длины строки (размера буфера через ReallocMem) у тебя все равно остаются. Эти тормоза особенно могут/будут проявляться в ранних версиях дельфей (в частности в D7), не использующих менеджер памяти FastMM. Поэтому лучше не наращивать длину строки на каждом найденном символе Result:=Result+..., а сразу выделить длину строки с некоторым (достаточно большим) запасом через SetLength(Result,...) и затем копировать в нее куски исходной строки простым Move(S[beforePos],Result[i],N), где N=(sPos-beforePos)*SizeOf(S[1]). Примерно так:
                            ExpandedWrap disabled
                              //поиск символа в AnsiString или в Utf8String (при условии, что Ord(C) < 128)
                              function ScanChar(C:AnsiChar; const S:AnsiString; iStart:integer):integer;
                              var
                                p:pAnsiChar;
                              begin
                                Result:=0;
                                if iStart > Length(S) then
                                  Exit;
                                p:=@S[iStart];
                                while (p^ <> C) and (p^ <> #0) do
                                  inc(p);
                                if p^ <> #0 then
                                  Result:=p-pAnsiChar(@S[1])+1;
                              end;
                               
                              function PreXMLFast(const S: Utf8String): Utf8String;
                              const
                                LFrac = 8; //знаменатель дроби, на которую берется запас длины строки - L+(L div LFrac)
                              var
                                iStart,iEnd:integer;//нач. и конеч. позиции копирования
                                iRes:integer; //позиция записи в Result
                                L,LRes:integer; //длина исходной и результирующей строки
                                N:integer; //кол-во копируемых символов
                              begin
                                L:=Length(S);
                                LRes:=L + (L div LFrac); //длина рез.строки с запасом на (L div LFrac)
                                SetLength(Result,LRes);
                                iStart:=1;
                                iRes:=1;
                                repeat
                                  iEnd:=ScanChar('>',S,iStart);
                                  if iEnd > 0 then
                                  begin
                                    N:=iEnd-iStart+1;
                                    if iRes+N+2 > LRes then
                                    begin
                                      inc(LRes, (L-iStart)+((L-iStart) div LFrac));
                                      SetLength(Result,LRes);
                                    end;
                                    Move(S[iStart],Result[iRes],N);
                                    inc(iRes,N+2);
                                    Result[iRes-2]:=#13;
                                    Result[iRes-1]:=#10;
                                    iStart:=iEnd+1;
                                  end;
                                until iEnd = 0;
                                SetLength(Result,iRes-1); //устанавливаем реальную длину строки
                              end;

                            PS: Тут лучше вместо string использовать AnsiString или Utf8String, а преобразование в unicode (если нужно), делать потом.
                              Только надо не забывать, что ">" вполне себе легитимно может встречаться в значениях узлов, в комментариях, CDATA секциях и инструкциях.
                                Цитата Fr0sT @
                                Только надо не забывать, что ">" вполне себе легитимно может встречаться в значениях узлов, в комментариях, CDATA секциях и инструкциях.

                                да, верно. но у меня частный случай:)
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0475 ]   [ 16 queries used ]   [ Generated: 28.03.24, 19:10 GMT ]