Форум: "Основная";
Текущий архив: 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