Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.10.10;
Скачать: [xml.tar.bz2];

Вниз

Функция поиска подстроки в строке на 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.039 c
1-1096013372
Koala
2004-09-24 12:09
2004.10.10
Опять про MDI приложение....


1-1095861749
DelphiLexx
2004-09-22 18:02
2004.10.10
Общедоступные паременные


10-1045474963
Vladimir
2003-02-20 11:03
2004.10.10
corba callback


14-1095421920
borrris
2004-09-17 15:52
2004.10.10
неужели в Москве приезжим так непросто?


1-1095843296
[BAD]Angel
2004-09-22 12:54
2004.10.10
Как убрать картинку с TImage?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский