Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.10.10;
Скачать: CL | DM;

Вниз

Функция поиска подстроки в строке на asmе   Найти похожие ветки 

 
lipskiy ©   (2004-09-21 01:27) [0]

Господа! Посмотрите код, не пойму, в чем ошибка.
Это функция поиска подстроки в строке.
Все работает, кроме когда подстрока задана одним символом маски * (звездочкой), при этом ничего не находит, хотя должна найти если в строке есть хоть какой-то текст. Остальные символы маски работают нормально, и если в подстроке звездочка в совокупности с другими символами - тоже нормально.

//##############################################################################
// Ищет первое вхождение Search в строке Sourse по маске, начиная с символа номер Start,
// возвращает номер позиции начала вхождения, 0 - вхождение не найдено
function ScanW(const Source,Search:AnsiString;var Start:integer):Integer;
//##############################################################################
{    "*" = любая строка включая пробелы
    "?" = любой символ
    "#" = любой цифровой символ (0..9)
    "@" = любой буквенный символ (a..z, A..Z)
    "$" = любой буквенно-цифровой символ
    "~" = любой не буквенно-цифровой символ
}
asm
 Push  EBX              //save the important stuff
 Push  ESI
 Push  EDI
 Push  EBP

 Mov   R1,ECX           //save Start address
 Or    EAX,EAX          //zero source ?
 Jz    @NotFound
 Or    EDX,EDX          //zero search ?
 Jz    @NotFound

 Mov   ESI,EAX          //source address
 Mov   L1,EAX           //save it in L1
 Mov   EDI,EDX          //search address
 Mov   ECX,[ECX]        //get start value
 Or    ECX,ECX          //case insensitive ?
 Jns   @L0              //no, then skip
 Neg   ECX              //absolute value of ECX
 Mov   EAX,-1           //set case flag
@L0:
 Dec   ECX              //zero based start position
 Js    @NotFound        //abort if less than zero

 Mov   EDX,[ESI-4]      //source length
 Or    EDX,EDX
 Jz    @NotFound        //abort on null string
 Sub   EDX,ECX          //consider only remaining of source
 Jbe   @NotFound        //abort if source is too short
 Add   ESI,ECX          //start at the given offset

 Mov   ECX,[EDI-4]      //search length
 Or    ECX,ECX
 Jz    @NotFound        //abort on null string
 Mov   L2,ECX           //save it in L2
 Mov   ECX,EDX          //source length in ECX
 Xor   EBX,EBX          //source offset
 Xor   EDX,EDX          //search offset
 Xor   EBP,EBP
 Mov   R2,EDX           //zero our anchor
@Next:
 Cmp   EDX,L2           //end of search ?
 Jz    @Found           //yes, we found it!

 Mov   AH,[EDI+EDX]     //get next character from search
 Inc   EDX              //next offset

 Cmp   AH,42            //wildcard "*"
 Jnz   @L1              //no, then skip
 Mov   R2,EDX           //drop anchor here
 Mov   EBP,EBX
 Jmp   @Next            //get next character

@L1:
 Cmp   EBX,ECX          //end of source ?
 Ja    @NotFound        //yes, then time to go

 Mov   AL,[ESI+EBX]     //get next character from source
 Inc   EBX              //next offset

 Cmp   AH,63            //wildcard "?"
 Jz    @Next            //yes, then check next char.
@L3:
 Cmp   AH,35            //wildcard "#"
 Jnz   @L5
 Cmp   AL,48
 Jb    @L4
 Cmp   AL,57
 Jbe   @Next
 Jmp   @L4
@L5:
 Cmp   AH,64            //wildcard "@"
 Jnz   @L6
 Cmp   AL,32
 Jz    @L4

 Push  EBX
 Lea   EBX,AlphaT

 Call  _TstBit
 Pop   EBX
 Jc    @Next
 Jmp   @L4
@L6:
 Cmp   AH,126            //wildcard "~"
 Jnz   @L7

 Push  EBX
 Lea   EBX,AlphaNumT
 Call  _TstBit
 Pop   EBX
 Jnc   @Next
 Jmp   @L4
@L7:
 Cmp   AH,36            //wildcard "$"
 Jnz   @L8
 Cmp   AL,32
 Jz    @L4

 Push  EBX
 Lea   EBX,AlphaNumT
 Call  _TstBit
 Pop   EBX
 Jc    @Next
 Jmp   @L4
@L8:
 Cmp   AL,AH            //match ?
 Jz    @Next            //yes, then check next char.

 Test  EAX,$80000000    //case insensitive flag
 Jz    @L4

 Push  EAX
 Call  RChar
 Mov   [ESP],AL
 Pop   EAX
 Cmp   AL,AH            //match ?
 Jz    @Next            //yes, then check next char.

@L4:
 Mov   EBX,EBP          //roll back Source offset
 Mov   EDX,R2           //roll back Search
 Or    EDX,EDX          //anchored ?
 Jz    @L2              //no, then skip
 Inc   EBP              //increment offset instead of base
 Inc   EBX
 Jmp   @Next
@L2:
 Inc   ESI              //move to next character in source
 Dec   ECX
 Jnz   @Next

@NotFound:
 Xor   EAX,EAX          //clear return
 Mov   ESI,EAX
 Jmp   @Done            //and bail
@Found:
 Sub   ESI,L1           //calc offset
 Inc   ESI
 Mov   EAX,EBX          //match length
@Done:
 Mov   EDI,R1           //Start = offset
 Mov   [EDI],ESI

 Pop   EBP              //restore the world
 Pop   EDI
 Pop   ESI
 Pop   EBX
end;


 
lipskiy ©   (2004-09-21 01:27) [1]


//##############################################################################
// для ScanW
procedure _TstBit;
//##############################################################################
asm
 Push  EDX
 Push  EAX
 And   EAX,255
 Mov   EDX,EAX
 And   EDX,7           //bit index
 Shr   EAX,3           //byte index
 Mov   AL,[EBX+EAX]    //get byte
 Bt    EAX,EDX         //test the bit
 Pop   EAX
 Pop   EDX
end;

//##############################################################################
// для ScanW
function RChar(const Source:Char):Char;
//##############################################################################
 {Reverse the case (lower to upper or upper to lower) of a single character
  using user-defined table.}
begin
 Result:=RevCase[Ord(Source)];
end;

//##############################################################################
// для ScanW
procedure GetSeps;
//##############################################################################
var
 I,J,K:Integer;
 Buffer: array[0..1] of Char;
 Locale: LCID;
begin
 Locale := GetThreadLocale;
 if GetLocaleInfo(Locale, LOCALE_SDECIMAL, Buffer, 2) > 0 then
   DecSep:=Buffer[0] else DecSep:=".";
 if GetLocaleInfo(Locale, LOCALE_STIME, Buffer, 2) > 0 then
   TimeSep:=Buffer[0] else TimeSep:=":";
 if GetLocaleInfo(Locale, LOCALE_SDATE, Buffer, 2) > 0 then
   DateSep:=Buffer[0] else DateSep:="/";
 if GetLocaleInfo(Locale, LOCALE_STHOUSAND, Buffer, 2) > 0 then
   ThouSep:=Buffer[0] else ThouSep:=",";
 for I:=0 to 31 do begin
   AlphaT[I]:=0;
   LowT[I]:=0;
   UprT[I]:=0;
 end;
 for I:=0 to 255 do begin  //build default ASCII case tables
   RevCase[I]:=Char(I);
   LowCase[I]:=Char(I);
   UprCase[I]:=Char(I);
   K:=I AND 7;
   J:=I SHR 3;
   if ((I>=65) AND (I<=90)) or ((I>=192) and (I<=223)) then begin
     LowCase[I]:=Char(I XOR 32);
     RevCase[I]:=LowCase[I];
     SetByteBit(AlphaT[J],K);
     SetByteBit(UprT[J],K);
   end else if ((I>=97) AND (I<=122)) or ((I>=224) and (I<=255)) then begin
     UprCase[I]:=Char(I XOR 32);
     RevCase[I]:=UprCase[I];
     SetByteBit(AlphaT[J],K);
     SetByteBit(LowT[J],K);
   end;
 end;
 AlphaT[4]:=1; //include space character
 for I:=0 to 31 do AlphaNumT[I]:=AlphaT[I] OR NumT[I];  //combine these two
end;

//##############################################################################
// для ScanW
procedure SetByteBit(var X:Byte;Cnt:Byte);
//##############################################################################
 {Set the Cnt bit (least significant = 0) of byte X.}
 asm
   Mov   CL,[EAX]
   Bts   ECX,EDX
   Mov   [EAX],CL
 end;


 
Defunct ©   (2004-09-21 04:25) [2]

Код просто ужасный.

Mov   ESI,EAX          //source address
Mov   EDI,EDX          //search address
Так нельзя делать, выключите оптимизацию и хана.

Mov   AL,[ESI+EBX]     //get next character from source
Есть сторовая команда LODS

Mov   AH,[EDI+EDX]     //get next character from search
Так вообще никто не делает, с AH накладно работать.

Когда вы проверяете строки, а тем более ищете подстроку в строке надо пользоваться строковыми командами LODS/STOS/SCAS/MOVS/CMPS
Для вашей задачи (честно сказать, я не особо понял, что должна выполнять ваша функция) CMPS или SCAS должны импользоваться обязательно.

Ваш код должен выглядеть примерно так:

Lea EDI, Where       ; где ищем (строка)
Mov   ECX, <SizeOF(Where)>

< Начало сканирования >
Lea ESI, What        ; то что ищем (подстрока)
Lodsb
RepNE SCASB

< Пока то что ищем не пусто >
< Сканирование >
Lodsb
Scasb
Jnz <не совпадает>
Cmp < Не вышли за границу подстроки >
Jz  < Сканирование >
Jmp < Выход >

<Не совпадает >
JCXNZ < Начало сканирования >

< Выход >
Нашли если ECX > 0


 
Defunct ©   (2004-09-21 04:38) [3]

PS: пишите лучше на Паскале, а то с асмом у вас явные проблемы. Понимаете, недостаточно знать одну команду MOV чтобы сделать все на свете. Тем более искать ошибку забесплатно в километровом коде, который состоит из одной команды MOV никто не будет.


 
Defunct ©   (2004-09-21 04:53) [4]

> Все работает, кроме когда подстрока задана одним символом маски * (звездочкой)

Блин тривиальное решение проблемы - заплатка.
при входе в функцию:

Cmp Word ptr Search, "*"
jz  < выдать всю входную строку как результат >


< тут имеющийся код вашей функции >

< выдать всю входную строку как результат >
Cld
Mov   AL, 0
Lea   EDI, Source
Push  EDI
Repne Scasb
Pop   ECX
Sub   EDi, ECx
Mov   Start, EDi
Mov   Result, 1
Ret


 
lipskiy ©   (2004-09-21 12:33) [5]


> Cmp Word ptr Search, "*"
> jz  < выдать всю входную строку как результат >
>
> < тут имеющийся код вашей функции >
>
> < выдать всю входную строку как результат >

Спасибо!!!
Об этом я совсем не подумал.
А код этот не мой, я асм вообще не знаю, где-то надыбал и пользую. Работает быстрее, чем на паскале, и не ошибается, мне этого достаточно.



Страницы: 1 вся ветка

Текущий архив: 2004.10.10;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.051 c
1-1096259413
POSO
2004-09-27 08:30
2004.10.10
Выбранный компонент


1-1096027583
GanibalLector
2004-09-24 16:06
2004.10.10
Word


1-1096312758
Kolan
2004-09-27 23:19
2004.10.10
Что за ф-ция INC


14-1095739399
R.O.O.T
2004-09-21 08:03
2004.10.10
Бесконечное сжатие


1-1096008720
RoLeX2004
2004-09-24 10:52
2004.10.10
Как проверить соответствует ли имя файла заданной маске?