字符串处理是我们在学习一门语言时不可或缺的练习,下面我们介绍几个简单的处理程序。
拷贝
功能简介:
功能:
拷贝字符串,接受任意目的地址
可在MAIN中设置目的地址相对源
地址位置
样例:
请在debug模式验证
代码演示:
;stack segment define
STACK1 SEGMENT PARA STACK
STACK_AERE DW 100H DUP(?)
STACK_BTM EQU $ - STACK_AERE
STACK1 ENDS
;data segment define
DATA1 SEGMENT
BUF DB 10H DUP(0)
SRC DB 'Hello, x86!'
DB '$'
LEN EQU $ - SRC
DST DB LEN DUP(0)
DATA1 ENDS
CODE1 SEGMENT
ASSUME CS:CODE1, SS:STACK1, DS:DATA1
;STRLEN PROC
;STRLEN ENDP
;源地址SI,目的地址DI,拷贝长度CX
STRCPY PROC
PUSH ES ;维护ES
PUSH DS
POP ES ;ES与DS处于同一个段
MOV BX, SI ;暂存SI
CMP SI, DI
JZ BRK
JAE FORDER ;SI >= DI -> forward
ADD SI, CX
DEC SI
CMP SI, DI ;SI+LEN<=DI -> forward
JBE FORDER
BACKER: STD
ADD DI, CX
DEC DI
JMP CPY
FORDER: CLD
MOV SI, BX
JMP CPY
CPY: LODSB
STOSB
LOOP CPY
BRK: POP ES
RET
STRCPY ENDP
MAIN PROC FAR
MOV AX, STACK1
MOV SS, AX
MOV SP, STACK_BTM
MOV AX, DATA1
MOV DS, AX
;设置源地址和目的地址
MOV SI, OFFSET SRC
;MOV DI, OFFSET DST ;3---SRC+len<=DST
;2-start---SRC<DST<SRC+LEN
MOV DI, OFFSET SRC
ADD DI, LEN
SUB DI, 2
;2-end---SRC<DST<SRC+LEN
;1-start---DST<=SRC
;MOV DI, OFFSET SRC
;SUB DI, 2
;1-end---DST<=SRC
MOV CX, LEN
;拷贝字符串
CALL STRCPY
EXIT: MOV AH, 4CH
INT 21H
MAIN ENDP
CODE1 ENDS
END MAIN
查找、替换
功能简介:
功能:
输入母字符串,子字符串以及替换字符串
输出替换后的结果
样例:
输入:Hello world, my worlds.
world
-> x86
Hello x86, my x86s.
代码演示:
;stack segment define
STACK1 SEGMENT PARA STACK
STACK_AERE DW 100H DUP(?)
STACK_BTM EQU $ - STACK_AERE
STACK1 ENDS
;data segment define
DATA1 SEGMENT
FLAG DW 0 ;默认前移
DIFF DW 0 ;子串和替换串长度一致
RPSTR_BUF DB 20H
RPLEN DB ?
RPSTR DB 1EH DUP(?)
SBSTR_BUF DB 20H
SBLEN DB ?
SBSTR DB 1EH DUP(?)
SRC_BUF DB 0FFH
LEN DB ?
SRC DB 0FEH DUP(?)
BUFF_ DB 010H DUP(?)
DATA1 ENDS
CODE1 SEGMENT
ASSUME CS:CODE1, SS:STACK1, DS:DATA1
;将地址缓冲区首地址偏移存入DX
READ_STR PROC
MOV AH, 0AH
INT 21H
RET
READ_STR ENDP
REP_STR PROC
PUSH ES
PUSH DS
POP ES
MOV SI, OFFSET SRC
MOV CL, LEN
AND CX, 00FFH
LP_SRC: PUSH CX
PUSH SI
MOV CL, SBLEN ;获取子串长度
AND CX, 00FFH
MOV DI, OFFSET SBSTR
CLD
LP_CMP: CMPSB
JNZ CONTINUE
LOOP LP_CMP ;DS:[SI]==ES:[DI]->LP
POP BX ;匹配串初始位置
POP CX ;决定替换之后原串长度更新
SUB CL, SBLEN ;预置CX
SBB CH, 0
INC CX
PUSH CX
PUSH BX
CMP FLAG, 0
JZ MVFW ;剩余的串前移
MVBK: ADD SI, CX
DEC SI
MOV DI, SI
ADD DI, DIFF
STD
REP MOVSB
JMP REPLACE
MVFW: MOV DI, SI
SUB DI, DIFF
CLD
REP MOVSB
REPLACE: POP DI
MOV CL, RPLEN ;替换穿作为SI,原串作为DI
AND CX, 00FFH
MOV SI, OFFSET RPSTR
CLD
REP MOVSB
POP CX
MOV SI, DI
LOOP LP_SRC
CONTINUE: POP SI
INC SI
POP CX
LOOP LP_SRC
;显示处理结果
DEL_END: MOV BYTE PTR [SI], 24H
MOV AH, 9
MOV DX, OFFSET SRC
INT 21H
POP ES
RET
REP_STR ENDP
DISP_SP PROC
MOV AH, 2 ;打印空格
MOV DL, 0AH
INT 21H
MOV AH, 2 ;打印箭头
MOV DL, 2DH
INT 21H
MOV AH, 2 ;
MOV DL, 3EH
INT 21H
MOV AH, 2 ;打印空格
MOV DL, 20H
INT 21H
RET
DISP_SP ENDP
DISP_NL PROC
MOV AH, 2 ;打印空格
MOV DL, 0AH
INT 21H
RET
DISP_NL ENDP
MAIN PROC FAR
MOV AX, STACK1
MOV SS, AX
MOV SP, STACK_BTM
MOV AX, DATA1
MOV DS, AX
LEA DX, SRC_BUF ;SRC缓冲区首地址偏移
CALL READ_STR
CALL DISP_NL
LEA DX, SBSTR_BUF ;SBSTR子串缓冲区首地址偏移
CALL READ_STR
CALL DISP_SP
LEA DX, RPSTR_BUF
CALL READ_STR
CALL DISP_NL
MOV CL, SBLEN ;子串长度
AND CX, 00FFH
MOV BL, RPLEN ;替换串长度
AND BX, 00FFH
CMP BX, CX
JBE FW
MOV FLAG, 1 ;1代表后移
SUB BX, CX
MOV DIFF, BX
JMP RP
FW: SUB CX, BX
MOV DIFF, CX
RP: CALL REP_STR
EXIT: MOV AH, 4CH
INT 21H
MAIN ENDP
CODE1 ENDS
END MAIN
大小写转换
功能简介:
功能:
不区分大小写查找字符串
并输出所有index,若无匹配返回~
输入:母字符串
子字符串
输出:查找结果列表,
样例:
输入:Tommy! Leave My tiMMy.
my
输出:3D 13D 19D
代码演示:
;stack segment define
STACK1 SEGMENT PARA STACK
STACK_AERE DW 100H DUP(?)
STACK_BTM EQU $ - STACK_AERE
STACK1 ENDS
;data segment define
DATA1 SEGMENT
SBSTR_BUF DB 20H
SBLEN DB ?
SBSTR DB 1DH DUP(?)
SRC_BUF DB 07FH
LEN DB ?
SRC DB 07CH DUP(?)
FLAG DW 0
DATA1 ENDS
CODE1 SEGMENT
ASSUME CS:CODE1, SS:STACK1, DS:DATA1
;将地址缓冲区首地址偏移存入DX
READ_STR PROC
PUSH ES
PUSH DS
POP ES
MOV AH, 0AH
INT 21H
MOV SI, DX
INC SI ;加1获得len
MOV CL, [SI]
AND CX, 00FFH
INC SI ;位移到字符串起始地址
MOV DI, SI
CLD
LP1: LODSB
CMP AL, 'a'
JB CONTINUE_RD
CMP AL, 'z'
JA CONTINUE_RD
SUB AL, 20H
CONTINUE_RD:STOSB
LOOP LP1
POP ES
RET
READ_STR ENDP
DISP_NL PROC
MOV AH, 2 ;打印换行
MOV DL, 0AH
INT 21H
RET
DISP_NL ENDP
;将AX中的数以10进制显示
DISP_10 PROC NEAR
MOV CX, 0
LP_10_real: MOV DX, 0
MOV BX, 10
DIV BX ;商在AX,余数在DX
PUSH DX ;余数入栈
INC CX
CMP AX, 0
JNZ LP_10_real
LP_10_num: POP AX
AND AL, 0FH
ADD AL, 30H
MOV AH, 2
MOV DL, AL
INT 21H
LOOP LP_10_num
MOV AH, 2 ;打印10进制末尾D
MOV DL, 44H
INT 21H
MOV AH, 2 ;打印空格
MOV DL, 20H
INT 21H
RET
DISP_10 ENDP
FIND PROC
PUSH ES
PUSH DS
POP ES
MOV SI, OFFSET SRC
MOV CL, LEN ;获得母字符串长度
AND CX, 00FFH
LP_SRC: PUSH CX
PUSH SI
MOV CL, SBLEN
AND CX, 00FFH
MOV DI, OFFSET SBSTR
CLD
LP_CMP: CMPSB
JNZ CONTINUE_FD
LOOP LP_CMP ;DS:[SI]==ES:[DI]->LP
MOV FLAG, 1 ;标记成功匹配
POP AX ;匹配串初始位置,需打印
MOV BX, OFFSET SRC
SUB AX, BX
;PUSH AX
CALL DISP_10
;POP SI
POP CX ;决定替换之后原串长度更新
SUB CL, SBLEN ;预置CX
SBB CH, 0
INC CX
LOOP LP_SRC
; PUSH CX
; PUSH BX
CONTINUE_FD:POP SI
INC SI
POP CX
LOOP LP_SRC
CMP FLAG, 1
JZ BRK
MOV AH, 2 ;打印~表示不匹配
MOV DL, 7EH
INT 21H
BRK: MOV AH, 2 ;打印换行
MOV DL, 0AH
INT 21H
POP ES
RET
FIND ENDP
MAIN PROC FAR
MOV AX, STACK1
MOV SS, AX
MOV SP, STACK_BTM
MOV AX, DATA1
MOV DS, AX
LEA DX, SRC_BUF ;SRC缓冲区首地址偏移
CALL READ_STR ;读字符串并将小写变成大写
CALL DISP_NL
LEA DX, SBSTR_BUF ;SBSTR子串缓冲区首地址偏移
CALL READ_STR
CALL DISP_NL
CALL FIND
EXIT: MOV AH, 4CH
INT 21H
MAIN ENDP
CODE1 ENDS
END MAIN
字典排序
功能简介:
功能:
输入多个字符串(由字母组成),
以空格间隔、回车结束,
输出排序后的结果
样例:
输入:
My name is Echo
输出:
ECHO IS MY NAME
代码演示:
;stack segment define
STACK1 SEGMENT PARA STACK
STACK_AERE DW 100H DUP(?)
STACK_BTM EQU $ - STACK_AERE
STACK1 ENDS
;data segment define
DATA1 SEGMENT
IN_MSG DB 'Please input strings separated by SPACE and ended by ENTER:(only letters)','$'
OUT_MSG DB 'The dictionary sort result is:', '$'
TMP_BUF DB 10H DUP(0)
TMP_LEN DW 0
STR_ARR DB 0FFH
DB ?
STRS DB 0FCH DUP(0)
ARR_LEN DW 0
CMP_FLAG DW 0 ;0-不需要排序,1-需要排序
;INDEX_ARR DW 0FFH DUP(0)
DATA1 ENDS
CODE1 SEGMENT
ASSUME CS:CODE1, SS:STACK1, DS:DATA1
;将地址缓冲区首地址偏移存入DX
READ_STR PROC
PUSH ES
PUSH DS
POP ES
MOV AH, 0AH
INT 21H
;LEA BX, INDEX_ARR
MOV SI, DX
INC SI ;加1获得len
MOV CL, [SI]
AND CX, 00FFH
INC SI ;位移到字符串起始地址
; MOV [BX], SI
; ADD BX, 2
MOV DI, SI
CLD
LP1_RD: LODSB
CMP AL, 'a'
JB CONTINUE_RD
CMP AL, 'z'
JA CONTINUE_RD
SUB AL, 20H
CONTINUE_RD:CMP AL, 20H
JNZ CONTINUE_R
INC ARR_LEN
;MOV [BX], SI
;ADD BX, 2
CONTINUE_R: STOSB
LOOP LP1_RD
MOV BYTE PTR [DI], 20H
; MOV BYTE PTR [DI+1], 0DH
MOV BYTE PTR [DI+1], '$'
INC ARR_LEN
POP ES
RET
READ_STR ENDP
DICSORT PROC
LP1_DIC: MOV AX, 1 ;标志位
LEA SI, STRS ;首个字符串起始index
MOV CX, ARR_LEN ;字符串的个数
DEC CX ;冒泡排序,比较n-1次
MOV DI, SI ;取两个index,DI为前字符串,SI为后字符串
LP2_DIC: ;MOV SI, [BX+2]
CALL GET_NEXT ;从SI指向的字符串开始,将下一个字符串的指针存在SI中
CALL DIC_CMP ;比较并按两个输入字符串,指针为DI,SI[不能改变DI,SI],结果存入CMP_FLAG
CMP CMP_FLAG, 0
JZ CONTINUE_DIC
CALL CHG_STR ;交换SI,DI的两个字符串
XOR AX, AX ;设立FLAG表示已交换
CONTINUE_DIC:
MOV DI, SI
LOOP LP2_DIC
CMP AX, 1
JZ EXIT_DIC
JMP LP1_DIC
EXIT_DIC: RET
DICSORT ENDP
CHG_STR PROC
PUSH ES
PUSH AX
PUSH CX
PUSH DI
PUSH SI
PUSH DS
POP ES
;前字符串拷贝到TMP中
MOV CX, SI
SUB CX, DI ;获得前字符串的长度
MOV TMP_LEN, CX
MOV SI, DI ;设定源地址
LEA DI, TMP_BUF
CALL STRCPY
;后字符串拷贝到前字符串中
POP SI ;将后字符串取出作为源地址
MOV AX, SI ;将SI暂存到AX中
POP DI ;前字符串取出作为目的地址
PUSH DI ;入栈保存
;PUSH SI
CALL GET_NEXT ;获得后字符串长度
MOV CX, SI
SUB CX, AX
MOV SI, AX ;将AX返还给SI
CALL STRCPY ;由于是++拷贝,故拷贝完之后的DI作为下一次拷贝的目的地址
PUSH DI ;DI是下一个字符串新的起始地址,即CONTINUE_DIC中应该更新的SI
;将前字符串拷贝到后字符串中
LEA SI, TMP_BUF
MOV CX, TMP_LEN
CALL STRCPY
POP SI
POP DI
POP CX
POP AX
POP ES
RET
CHG_STR ENDP
;源地址SI,目的地址DI,拷贝长度CX
STRCPY PROC
PUSH ES ;维护ES
PUSH DS
POP ES ;ES与DS处于同一个段
MOV BX, SI ;暂存SI
CMP SI, DI
JZ BRK
JAE FORDER ;SI >= DI -> forward
ADD SI, CX
DEC SI
CMP SI, DI ;SI+LEN<=DI -> forward
JBE FORDER
BACKER: STD
ADD DI, CX
DEC DI
JMP CPY
FORDER: CLD
MOV SI, BX
JMP CPY
CPY: LODSB
STOSB
LOOP CPY
BRK: POP ES
RET
STRCPY ENDP
GET_NEXT PROC
PUSH ES
PUSH AX
PUSH DS
POP ES
CLD
LP_NEXT: LODSB
CMP AL, 20H ;若是单个字符串结尾,则+1记录为下一个字符串开始index
JNZ LP_NEXT
POP AX
POP ES
RET
GET_NEXT ENDP
;比较并按两个输入字符串,指针为DI,SI
DIC_CMP PROC
PUSH ES
PUSH AX
;PUSH BX
PUSH CX
PUSH SI
PUSH DI
PUSH DS
POP ES
MOV CX, SI
SUB CX, DI ;将前一个字符串的长度作为比较长度
CLD
MOV CMP_FLAG, 0 ;清空排序标志位(两个内存数不能操作)
LP_CMP: CMPSB
JZ CONTINUE_CMP
;JA CMP1
JA EXIT_CMP ;DI在前,SI在后,故采用JA
MOV CMP_FLAG, 1
JMP EXIT_CMP
CONTINUE_CMP:
LOOP LP_CMP
EXIT_CMP: POP DI
POP SI
POP CX
;POP BX
POP AX
POP ES
RET
DIC_CMP ENDP
HINTS PROC
MOV AX, DATA1
MOV DS, AX
;LEA DX, STRS
MOV AH, 9
INT 21H
MOV AH, 2 ;打印回车
MOV DL, 0AH
INT 21H
RET
HINTS ENDP
MAIN PROC FAR
MOV AX, STACK1
MOV SS, AX
MOV SP, STACK_BTM
MOV AX, DATA1
MOV DS, AX
;input hints
LEA DX, IN_MSG
CALL HINTS
LEA DX, STR_ARR
CALL READ_STR ;读字符串并统一为大写
CALL DICSORT
MOV AH, 2 ;打印回车
MOV DL, 0AH
INT 21H
;ouput hints
LEA DX, OUT_MSG
CALL HINTS
;output disp
LEA DX, STRS
CALL HINTS
EXIT: MOV AH, 4CH
INT 21H
MAIN ENDP
CODE1 ENDS
END MAIN
以上便是关于字符串操作的x86程序演示,引用请注明出处(https://echo-ji.github.io/2018/05/14/x86-字符串处理/)。