汇编:用另一个字符串

时间:2016-08-17 21:22:20

标签: string assembly replace substring

你好我是汇编中的新手,我在练习中遇到一些问题,要求我在原始字符串中找到子字符串然后,如果找到,则将其替换为另一个给定的字符串,但仅用于奇数事件发现(1,3,5 ......)。即。

  • 原始字符串:" abc world def world"。
  • 要查找的字符串:" world"
  • 字符串替换:" cat"
  • 输出:" acb cat def world"

此外,这些应适用于所有类型的输入。即使像这种情况一样," world"比{" cat"'更长,我需要更换" world"完全(" catld"会错)。 谁能帮我?!我不知道如何处理。 这是我目前的代码,我还没有考虑奇怪的事情,我只是想让它发挥作用:

#include <stdio.h>

void main() {

    //Input
    char stringa[1024] ="This string is a string\n";
    char str1[] ="string";  
    char str2[] ="cat"; 

    //Output
    char result[1024];

    __asm {

        XOR EAX, EAX
        CLD
        LEA ESI, str1
        LEA EDI, stringa
Ciclo:  MOV AL, [ESI]
        REPNZ SCASB
        DEC EDI
        PUSH EDI
        PUSH ESI
        MOV ECX, 7
        REPE CMPSB
        CMP ECX, 0
        POP ESI
        JZ Sost
        JMP Ciclo

Sost:   LEA ESI, str2
        POP EDI
        MOV ECX, 7
        REP MOVSB
    }

    printf("New string: %s\n",result);
}

4 个答案:

答案 0 :(得分:3)

我认为这样的事情: 输入:原始字符串,要查找的子字符串,用于替换的子字符串,输出字符串

  1. 将EDI设置为原始字符串指向的第一个字节
  2. 将ESI设置为子字符串指向的第一个字节以查找
  3. 将AL移动到第一个子字符串字节
  4. 读取原始字符串,直到与要查找的给定子字符串的第一个字符不同(SCASB)。
  5. 虽然不同,但请将每个字符复制到输出字符串中。
  6. 当/如果匹配时,将ECX设置为子串长度。
  7. 比较原始字符串和子字符串,从第一个匹配点开始。
  8. 检查ECX。
  9. 如果ECX为零,我发生了一次,请转到Checkpoint。
  10. 转到第4点。
  11. 检查点:a)增量发生计数器              b)检查计数器。              c)如果奇怪去替换。              d)转到第4点

    替换:a)将ECX设置为替换字符串长度              b)在输出字符串中复制替换字符串              c)转到第4点

    它看起来如何?

答案 1 :(得分:3)

下一个代码完成工作:它找到并替换另一个字符串的所有(非奇数)出现,并将结果字符串保留在另一个变量中,在编译器EMU8086中测试它(我的VS不工作),代码后面的解释:

.model small
.stack 100h
.data
original db 'abc world def world xyz',0
find     db 'world',0
subst    db 'cat',0
result   db 100 dup(0)
i        dw ?             ;INDEX FOR "ORIGINAL".
j        dw ?             ;INDEX FOR "RESULT".
.code
   mov  ax, @data
   mov  ds, ax
   mov  i, offset original ;"I" POINTS TO "ORIGINAL".
   mov  j, offset result   ;"J" POINTS TO "RESULT".
;SEARCH VARIABLE "FIND" AT CURRENT POSITION ("I").
   mov  si, i
   lea  di, find
search:                        
   mov  al, [di]        ;CURRENT CHAR OF VARIABLE "FIND".
;CHECK IF END OF "FIND".
   cmp  al, 0           ;IF CURRENT CHAR OF "FIND" IS LAST ONE...
   je   match           ;... VARIABLE "FIND" WAS FOUND.
;CHECK IF END OF "ORIGINAL".
   cmp  [si], 0
   je   finale
;CONTINUE.   
   cmp  [si], al        ;CMP ORIGINAL[SI],FIND[DI].
   jne  mismatch        ;CHARS ARE DIFFERENT.
   inc  si              ;NEXT CHAR OF "ORIGINAL".
   inc  di              ;NEXT CHAR OF "FIND".
   jmp  search          ;REPEAT (COMPARE NEXT CHAR).
match:
;WHEN "FIND" IS FOUND, "SUBST" REPLACE IT IN "RESULT".
   mov  i, si           ;SKIP "FIND" IN "ORIGINAL", BUT...
   dec  i               ;...SKIPPED ON CHAR FORWARD (SO DECREASE).
   lea  di, subst       ;STRING TO REPLACE "FIND".
replace:
   mov  al, [di]        ;CURRENT CHAR OF VARIABLE "SUBST".
;CHECK IF END OF "SUBST".
   cmp  al, 0           ;IF CURRENT CHAR OF "FIND" IS LAST ONE...
   je   next
;CONTINUE.
   mov  si, j           ;CURRENT POSITION IN "RESULT".
   mov  [si], al        ;COPY CHAR INTO "RESULT[ J ]".
   inc  j               ;NEXT POSITION IN "RESULT".
   inc  di              ;NEXT POSITION IN "SUBST".
   jmp  replace
mismatch:    
;APPEND CURRENT CHAR (AL) INTO "RESULT".
   mov  si, i           ;CURRENT POSITION IN "ORIGINAL".
   mov  di, j           ;CURRENT POSITION IN "RESULT".
   mov  al, [si]
   mov  [di], al
   inc  j               ;"I" IS ALSO INCREMENTED 4 LINES BELOW.
;NEXT CHAR IN "ORIGINAL".
next:
   lea  di, find        ;SEARCH AGAIN VARIABLE "FIND".
   inc  i               ;NEXT CHAR IN "ORIGINAL".
;CHECK IF END OF "ORIGINAL".
   mov  si, i
   cmp  [si], 0
   jne  search          ;REPEAT (SEARCH "FIND" AGAIN).
;END OF WHOLE PROCESS.
finale:
   mov  ax, 4c00h
   int  21h

结果是:

original = `abc world def world xyz`
find     = `world`
subst    = `cat`
result   = `abc cat def cat xyz`

请注意,代码中的所有字符串(数据段中的变量)都使用0作为结束分隔符。这非常重要,因为这是处理任何大小的字符串的关键,而不是硬编码的大小。

现在算法:

  1. 它会循环播放&#34;原始&#34;。
  2. 中的每个字符
  3. 字符串&#34;找到&#34;在&#34;原始&#34;中的每个字符被搜索被访问了。
  4. 如果&#34;发现&#34;找不到,#34;原来&#34;附加在&#34;结果&#34;。
  5. 如果&#34;发现&#34;找到了,字符串&#34; subst&#34;附加在&#34;结果&#34;和&#34; i&#34; (指向&#34;原始&#34;的指针)跳到搜索循环结束的地方(减1),以便跳过我们想要替换的字符串。 &#34; J&#34; (指向&#34;结果&#34;的指针)从不跳过,它总是增加一个。
  6. 要使其适用于奇数事件,请添加另一个数字变量作为在标签match:下增加的计数器,如果变量在标签search:之后不是奇数,则使其跳转到标签{{1 }}

    编辑:现在是Visual Studio 2013版本(在&#34; C ++ Win32控制台应用程序和#34上测试;):

    next:

    编辑#2:以前的代码,变量#include "stdafx.h" #include "conio.h" int _tmain(int argc, _TCHAR* argv[]) { //Input char original[1024] = "abc world def world xyz\n"; char find[] = "world"; char subst[] = "cat"; //Output char result[1024] = { 0 }; int i; int j; _asm { lea esi, original mov i, esi // "I" POINTS TO "ORIGINAL". lea esi, result mov j, esi // "J" POINTS TO "RESULT". // SEARCH VARIABLE "FIND" AT CURRENT POSITION ("I"). mov esi, i lea edi, find search: mov al, [edi] // CURRENT CHAR OF VARIABLE "FIND". // CHECK IF END OF "FIND". cmp al, 0 // IF CURRENT CHAR OF "FIND" IS LAST ONE... je match // ... VARIABLE "FIND" WAS FOUND. // CHECK IF END OF "ORIGINAL". cmp [esi], 0 je finale // CONTINUE. cmp [esi], al // CMP ORIGINAL[SI],FIND[DI]. jne mismatch // CHARS ARE DIFFERENT. inc esi // NEXT CHAR OF "ORIGINAL". inc edi // NEXT CHAR OF "FIND". jmp search // REPEAT (COMPARE NEXT CHAR). match: // WHEN "FIND" IS FOUND, "SUBST" REPLACE IT IN "RESULT". mov i, esi // SKIP "FIND" IN "ORIGINAL", BUT... dec i // ...SKIPPED ON CHAR FORWARD (SO DECREASE). lea edi, subst // STRING TO REPLACE "FIND". replace: mov al, [edi] // CURRENT CHAR OF VARIABLE "SUBST". // CHECK IF END OF "SUBST". cmp al, 0 // IF CURRENT CHAR OF "FIND" IS LAST ONE... je next // CONTINUE. mov esi, j // CURRENT POSITION IN "RESULT". mov [esi], al // COPY CHAR INTO "RESULT[ J ]". inc j // NEXT POSITION IN "RESULT". inc edi // NEXT POSITION IN "SUBST". jmp replace mismatch: // APPEND CURRENT CHAR (AL) INTO "RESULT". mov esi, i // CURRENT POSITION IN "ORIGINAL". mov edi, j // CURRENT POSITION IN "RESULT". mov al, [esi] mov [edi], al inc j // "I" IS ALSO INCREMENTED 4 LINES BELOW. // NEXT CHAR IN "ORIGINAL". next: lea edi, find // SEARCH AGAIN VARIABLE "FIND". inc i // NEXT CHAR IN "ORIGINAL". // CHECK IF END OF "ORIGINAL". mov esi, i cmp [esi], 0 jne search // REPEAT (SEARCH "FIND" AGAIN). // END OF WHOLE PROCESS. finale: } printf("New string: %s", result ); _getch(); return 0; } i分别替换为jebx(我留下了评论所说的部分&#34;我& #34;和&#34; J&#34;所以你可以看到我做了替换的地方):

    ecx

答案 2 :(得分:0)

此代码有效,我尝试了很多输入。有很多重复的代码行,但它的工作原理。我会看看我能否在下一天减少它。正如我对Josè所说,我不能在输入中给出的4个字符串中添加变量:stringa(原始),str1(找到),str2(新子串),risultato(最终输出):

    __asm {
                XOR EAX, EAX
                XOR EBX, EBX
                XOR EDX, EDX
                CLD
                LEA EDI, str1
                LEA ESI, stringa

                Cicle : 
                        MOV AL, [ESI]
    //CHECK IF STRING ENDED
                        CMP AL, 0
                        JZ End
    //CHECK THE CHAR
                        SCASB
    //IF THEY DON'T MATCH GO TO COPY CHAR
                        JNZ Append
    //OTHERWISE CHECK IF FROM HERE STRINGS ARE EQUAL
                        MOV ECX, LENGTH str1
                        DEC EDI
                        REPE CMPSB
                        CMP ECX, 0
    //IF YES GO TO CHECK IF IT'S AN ODD OCCURRENCE
                        JZ Checkpoint
    //IF NOT GET BACK ESI AND EDI...
                        NEG ECX
                        ADD ECX, LENGTH str1
                        SUB EDI, ECX
                        SUB ESI, ECX
    //..AND COPY THE SINGLE CHAR
                        MOV risultato[EBX], AL
                        INC EBX
                        INC ESI
                        JMP Cicle

    //COPY CHAR WHEN STRINGS DONT'MATCH    
                Append :
                        INC ESI
                        DEC EDI
                        MOV risultato[EBX], AL
                        INC EBX
                        JMP Cicle

    //CHEK IF ODD/EVEN OCCURRENCE               
                Checkpoint :
                        INC EDX
                        TEST EDX, 00000001h
    //IF ODD GO TO REPLACE ALL SUBSTRING
                        JNZ Replacement
    //OTHERWISE GET BACK ESI/EDI AND COPY THE SAME SUBSTRING TO RESULT
                        SUB EDI, LENGTH str1
                        SUB ESI, LENGTH str1
                        PUSH EDI
                        LEA EDI, risultato[EBX]
                        MOV ECX, LENGTH str1
                        REP MOVSB
    //UPDATE RESULT INDEX COUNTER
                        ADD EBX, LENGTH str1 - 1
    //GET BACK EDI POINTER
                        POP EDI
                        DEC ESI
                        JMP Cicle

    //REPLACEMENT OF THE SUBSTRING                  
                Replacement :
    //GET BACK EDI AT FIRST CHAR AND STORE ESI/EDI FOR NEXT LOOP
                        SUB EDI, LENGTH str1
                        PUSH ESI
                        PUSH EDI
    //SET A POINTER TO THE NEW STRING AND COPY IT TO RESULT
                        LEA ESI, str2
                        LEA EDI, risultato[EBX]
                        MOV ECX, LENGTH str2
                        REP MOVSB
    //UPDATE RESULT COUNTER AND GET BACK EDI/ESI TO PREVIOUS POSITIONS TO CONTINUE
                        ADD EBX, LENGTH str2 - 1
                        POP EDI
                        POP ESI
                        DEC ESI
                        JMP Cicle

                End :
                        MOV risultato[EBX], 0
}

我已经忘记了一个细节:当我发现char'è'时,这段代码(在AL中)用ascii 232代替138,为什么呢?我能做什么? 感谢

答案 3 :(得分:0)

最后没关系。我使用Jose Manuel的代码(谢谢),我使用pop / push而不是变量“i”和“j”修改它。然后输入错误的在线测试:“ccccc”,“cc”,“f”。结果应为“fccc”,但为“fcf”。所以我修复了一些其他细节,现在没关系。

        XOR ECX, ECX
        XOR EAX, EAX
        XOR EBX, EBX
        XOR EDX, EDX
        LEA ESI, result
        PUSH ESI                //store result into stack
        LEA ESI, original       //esi points to original
        LEA EDI, find           //edi points to find

        Search :
            MOV AL, [EDI]
                CMP AL, 0           //chek if the end of find
                JE Match            //if yes, we have an occurrence
                CMP[ESI], 0         //check if end of original
                JE Mismatch         //if yes, coopy last char going to Mismatch
                CMP[ESI], al        //check if char match
                JNE Mismatch        //if yes go to Mismatch
                INC ESI             //else repeat Search to check if next char match
                INC EDI
                INC ECX             //chars counter
                JMP Search

        Match :
            INC EBX                 //occurrences counter
                TEST EBX, 00000001h
                JZ Mismatch         //if even go to Mismatch else continue...
                LEA EDI, str2       //else point to new string to replace
                MOV EDX, ESI        //copy the current original pointer
                POP ESI             //store it also into the stack

        Replacement :
            MOV AL, [EDI]           //copy new string char by char
                CMP AL, 0
                JE SetRegister      //if end of new string, get back the pointers
                MOV[ESI], AL        //else continue...
                INC ESI
                INC EDI
                JMP Replacement

        Mismatch :
            POP EDI                 //edi points to result
                SUB ESI, ECX        //set esi to the char it was pointing before Search or Match
                INC ECX             //shows how many chars we need to replace
                REP MOVSB           //ready to copy chars from original to result
                PUSH EDI
                CMP[ESI], 0         //check if original has ended
                JZ Fine
                DEC ESI
                XOR ECX, ECX        //set to zero the chars counter
                JMP Next            //go to Next char

        SetRegister :
            PUSH ESI                //after replacement set registers right positions
                MOV ESI, EDX
                DEC ESI
                XOR ECX, ECX

        Next :
            LEA EDI, find           //ready to find next char
                INC ESI
                CMP[ESI], 0
                JNE Search

        Fine :
            POP EDI
                MOV[EDI], 0         //close the result string

谢谢大家。