首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在汇编语言8086中用字符串替换一个字符

问在汇编语言8086中用字符串替换一个字符
EN

Stack Overflow用户
提问于 2022-09-06 07:43:40
回答 2查看 441关注 0票数 2

嗨,我正在用汇编语言8086制作这个程序,它可以检测'E‘,并将'E’替换成'Egg‘示例:英语:英语!用鸡蛋英语:蛋英语!以下是我的尝试:

代码语言:javascript
复制
.MODEL SMALL
.STACK 100H
.DATA
english DB "In English$"
result DB 100 dup(?)
;english DB "In english: English$"
;In english: You like english and espresso, excellent!
newline DB 10,13,'$'
bigegg DB "Egg$"
smallegg DB "egg$"

.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX

mov ah, 09h
lea dx, english
int 21h

mov ah, 09h
lea dx, newline
int 21h

lea si, english ;start from first char
lea di, result

mov cx, 19

loop1:
mov al, [si]
cmp al, 45h ;E
je bige
jne checke

bige:
mov bx, si
mov cx, si
loop2:
mov ah, 02h
mov dl, [di]
int 21h
loop loop2

inc si
mov ah, 09h
lea dx, bigegg
int 21h
jmp change

checke:
cmp al, 65h ;e
je smalle
jne again

smalle:
mov bx, si
mov cx, si
loop3:
mov ah, 02h
mov dl, [di]
int 21h
loop loop3

inc si
mov ah, 09h
lea dx, smallegg
int 21h
jmp change

again:
mov al, [si] ;save I
mov [di], al
inc si
inc di
loop loop1

change:
lea si, english + 3
sub cx, si
mov cx, cx

loop4:
mov ah, 02h
mov dl, [di]
int 21h
loop loop4

MOV AX, 4C00H
INT 21H

MAIN ENDP
END MAIN

实际上,我想让我的系统如下所示:如果检测到'e‘,系统首先会删除'In’,然后忽略'e‘,然后打印’鸡蛋‘和'nglish’。但是,当我运行我的代码时,它会打印出空白。如果有人能指点我,我很感激,谢谢你的阅读!

EN

回答 2

Stack Overflow用户

发布于 2022-09-06 10:03:17

这是我的解决办法。我故意没有对其进行过多的优化,以便以简单的方式显示循环的工作原理。它使用像nasm test.asm -o test.com这样的命令(它使用默认的-f bin隐式-f bin格式)组装成一个平面的-f bin格式文件。应该主要与另一个汇编程序一起工作。

我为子程序做了一些行注释和两个协议注释。

代码语言:javascript
复制
        cpu 8086
        org 256
start:
        mov dx, message
        mov cx, message_length
        call display

        mov dx, linebreak
        mov cx, linebreak_length
        call display

        mov si, message
chunkloop:
        mov dx, si              ; initialise offset of most recent chunk start

byteloop:
        mov al, byte [si]       ; get this byte
        cmp al, 'E'             ; check for replacement
        je big                  ; replace big letter -->
        cmp al, 'e'
        je small                ; replace small letter -->
        cmp al, 0               ; terminator ?
        je end                  ; yes, end -->
        inc si                  ; -> next byte
        jmp byteloop            ; loop back to scan next byte

big:
        call displaychunk       ; display chunk up to this
        mov dx, replace_big
        mov cx, replace_big_length
        call display            ; display replacement
        inc si                  ; -> next byte after what we replaced
        jmp chunkloop           ; jump back and re-initialise dx so it will
                                ;  get the start offset of the next chunk

small:                          ; (same code as for big, different replacement)
        call displaychunk
        mov dx, replace_small
        mov cx, replace_small_length
        call display
        inc si
        jmp chunkloop

end:
        call displaychunk       ; display the last chunk

        mov dx, linebreak
        mov cx, linebreak_length
        call display

        mov ax, 4C00h
        int 21h


                ; INP:  ds:dx -> most recent chunk
                ;       ds:si -> byte to be replaced (or terminator)
                ; REM:  Here si points to behind the last byte that we
                ;        want to write to display the chunk. Therefore
                ;        si minus dx is the length we want to write.
                ;       The chunk length may be zero (dx equals si).
displaychunk:
        mov cx, si              ; get offset behind the chunk
        sub cx, dx              ; calculate length of chunk
        jz emptychunk           ; if empty -->

                ; INP:  ds:dx -> message data
                ;       cx = length of message to write
display:
        mov bx, 1               ; = stdout handle
        mov ah, 40h
        int 21h                 ; write to file handle
emptychunk:
        retn



message:
        db "In english: English"
message_length equ $ - message
        db 0            ; terminator for main loop

replace_big:
        db "Egg"
replace_big_length equ $ - replace_big

replace_small:
        db "egg"
replace_small_length equ $ - replace_small

linebreak:
        db 13,10
linebreak_length equ $ - linebreak

一些可能的优化:

  • 共享大小写代码

  • 为所有控制流路径共享增量si

  • 使用lodsb同时从byte [ds:si]加载和增量lodsb

  • 动态地将要替换的字母写入替换字符串,以便从源消息

获得一个小或大的字母。

  • _length等价物可以使用NASM的本地标签来减少标签的键入量(为了更好地与其他汇编程序兼容而避免)

。

票数 3
EN

Stack Overflow用户

发布于 2022-09-11 13:42:30

您的代码中有很多错误,ecm的第一个注释总结了其中的大多数错误。我将不重复这一点,但提出了一个解决方案,该解决方案显示一个循环,其中主循环条件在循环(最小化分支)的底部进行测试,并且在循环主体中有附加条件伴随着(嵌套的循环)。

与其逐字符输出结果字符,甚至不是逐块输出结果,我一次都显示结果,同时还附带了一个包含的回车/ linefeed对和必要的$-结束符。为此,源字符串被转换为ASCIIZ字符串(以0结尾的字符串),其最后三个字节用于回车,10用于linefeed,36用于美元符号。(*)

该程序是一个.COM可执行文件。我使用FASM,但很少需要更改才能使用NASM。

与ecm的解决方案相比,我更接近OP使用在DOS下非常常见的以$结束的字符串的尝试。

代码语言:javascript
复制
    ORG  256

    mov  dx, english
    mov  ah, 09h       ; DOS.PrintString
    int  21h

    mov  si, english   ; Address of a zero-terminated string
    mov  di, result
    jmp  BottomOfLoop
TopOfLoop:
    mov  bx, bigegg
    cmp  al, "E"
    je   .b
    mov  bx, smallegg
    cmp  al, "e"
    je   .b
    mov  bx, empty

.a: stosb
.b: mov  al, [bx]
    inc  bx
    cmp  al, "$"
    jne  .a

BottomOfLoop:
    lodsb
    cmp  al, 0         ; Reached end of the ASCIIZ string ?
    jne  TopOfLoop     ; Not yet

    mov  dx, result    ; Address of a $-terminated string
    mov  ah, 09h       ; DOS.PrintString
    int  21h

    mov  ax, 4C00h     ; DOS.Terminate
    int  21h

english   db "In english: English", 13, 10, "$", 0       ; (*)
bigegg    db "Egg$"
smallegg  db "egg"
empty     db "$"

result    rb 100

使用rb (对NASM使用resb ),可以避免在文件中包含结果缓冲区,从而使最终的可执行文件保持较小。通常,小型文件加载速度要快一些。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73618421

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档