(MASM) Удаление второй подстроки из первой и сохранение результата третью - Assembler
Формулировка задачи:
Здравствуйте! Три дня ломал голову над задачей и все-таки решил прибегнуть к вашей помощи.
Даны три строки, S1, S2, S3. Удалить из S1 первое появление S2, остаточную строку записать в S3. Вывести все три строки.
Вот мои безуспешные попытки
include Irvine32.inc
Show macro string
lea edx, string
call WriteString
call Crlf
endm
.data
S1 db '3331234222222453322222222345',0
S2 db '345',0
S3 db sizeof S1 dup(0)
len_S2 dd ?
len_S1 dd ?
s3_edi dd ?
.code
main proc
Show S1
;lab S1, S2, S3
cld
mov edi, offset S2
Invoke Str_length, edi
mov len_S2, eax
mov edi, offset S1
Invoke Str_length, edi
mov len_S1, eax
lea edi, S3
mov s3_edi, edi
lea esi, S1
lea edi, S2
srch:
lea edi, S2
mov ecx, len_S2
repe cmpsb
jne mismatch
jmp ext
mismatch:
pusha
dec esi
dec edi
lodsb
mov edi, s3_edi
stosb
popa
inc s3_edi
jmp srch
ext:
Show S2
Show S3
exit
main endp
end mainРешение задачи: «(MASM) Удаление второй подстроки из первой и сохранение результата третью»
textual
Листинг программы
org 100h jmp start Str1 db 'ANBC-HD*G_HJV0125800 BKMC4 NX3451185ABCGEF00245',0 len1 = ($ - Str1)-1 ; длина строки (без нуль-терминала) Str2 db '345',0 len2 = ($ - Str2)-1 Str3 db 80 dup(0) crlf db 13,10,'$' start: mov bx,len1 ; BX = длина строки xor ax,ax ; плавающая позиция xor dx,dx ; это будет найденая позиция в строке @@: ; mov si,Str1 ; указатель на строку mov di,Str2 ; ..и на под/строку mov cx,len2 ; длина под/строки add si,ax ; добавляем плавающую позицию mov dx,si ; запоминаем эту позицию repe cmpsb ; сравниваем строки jz @f ; переход, если есть вхождение inc ax ; иначе: позиция поплыла вперёд dec bx ; ..а счётчик назад jnz @b ; если не конец строки, то циклимся.. ; ошибка поиска! ====================================================// mov al,7 ; бипер, int 29h ; jmp exit ; ..и на выход! ; Есть вхождение! ; На этом этапе SI установлен на первом/найденном символе, плюс длина под/строки. ; DX указывает на первый/найденный символ. @@: ; mov di,dx ; вставляем по-адресу DX, xor al,al ; ..нуль-терминал (отрезали хвост). stosb ; lea cx,[Str1+len1] ; вычисляем длину хвоста sub cx,dx ; sub cx,len2 ; ..без под/строки mov di,Str3 ; DI приёмник, SI источник rep movsb ; копируем СХ-байт из SI в DI mov si,Str1 ; выводим на экран получившиеся строки call WriteString ; эта функция выводит строку на консоль (по-байтно), mov si,Str2 ; ..пока не встретится нуль-терминал. call WriteString ; mov si,Str3 ; call WriteString ; exit: ; xor ax,ax ; int 16h ; int 20h ; на выход! ;ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн WriteString: ; mov dx,crlf ; курсор на новую строку mov ah,9 ; int 21h ; @@: ; lodsb ; читаем байт из SI or al,al ; нуль-терминал? jz @f ; int 29h ; нет - печатаем символ. jmp @b ; @@: ; ret ;
Объяснение кода листинга программы
Код на языке Assembler выполняет удаление второй подстроки из первой и сохранение результата третьей. Список действий:
- Переменная
len1содержит длину строкиStr1(включая нуль-терминал), вычисленную как разность междуStr1и нуль-терминалом. - Переменная
len2содержит длину подстрокиStr2, вычисленную как разность междуStr2и нуль-терминалом. - Переменная
Str3содержит результат, который будет отправлен на консоль. - В цикле сравниваются символы строки
Str1и подстрокиStr2. Если символы совпадают, то увеличивается счётчик совпадений в регистреbx. - Если счётчик совпадений равен нулю, то регистры
siиdiинкрементируются на длину подстроки, и цикл продолжается. - Если счётчик совпадений не равен нулю, то увеличивается регистр
ax, который является плавающей позицией в строке. - Делается переход на начало цикла, чтобы продолжить поиск совпадений.
- Если счётчик совпадений равен нулю, то делается переход на выход из программы.
- Если счётчик совпадений не равен нулю, то происходит копирование символов из строки
Str1в строкуStr3. - Выводится на консоль строка
Str3.