Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Центр помощи > [ASM] Задача на строки


Автор: octopus 4.11.2010, 00:52
Господа программисты! Была бы очень признательна, если бы Вы помогли с задачкой! Не предстваляю, как организовать подобное на Ассемблере... smile   А надо...Вы моя последняя надежда!
Суть задачи: Дан массив запрещенных слов и предложение, в котором могут быть(или не быть) эти самые слова. Нужно удалить слова из предложения. Можно использовать 2 строки(2ая для результата). Также можно потребовать точку, как признак конца исходного предложения. 
Заранее спасибо!

Автор: iff 5.11.2010, 17:06
Какая ОС? Компилятор? Процессор?


Для DOS, компиятор TASM, процессор Intel 8086+
Код

    .MODEL    SMALL
    .STACK    32H
    .DATA

DELIMITER    DB    ' .,?!;:-', 0DH, 0AH, 09H
DELIMITERL    DW    $ - OFFSET DELIMITER    ;*

MASS    LABEL    BYTE    ;*
E1    DB    'QWERTY'
E2    DB    'ASD'
E3    DB    'FGG'
E4    DB    'KKL'
MASSEND    LABEL    BYTE    ;*

MASSL    DB    OFFSET E2 - OFFSET MASS
    DB    OFFSET E3 - OFFSET E2
    DB    OFFSET E4 - OFFSET E3
    DB    OFFSET MASSEND - OFFSET E4

MASSADR    DW    OFFSET E1
    DW    OFFSET E2
    DW    OFFSET E3
    DW    OFFSET E4

MASSLE    DW    4

OLDSINDEX    DW    OFFSET STRIN    ;*
MASSINDEX    DW    0    ;*

NEWLINE    DB    0DH, 0AH, '$'    ;*

INPUTBUFER    LABEL    BYTE    ;*
MAXLEN    DB    0FFH    ;*
LEN    DB    ?    ;*
STRIN    DB    0FFH DUP (?)    ;*

    .CODE
MAIN:
    MOV    AX,@DATA    ;Инициализация сегмента данных
    MOV    DS,AX
    MOV    ES,AX

    MOV    AH,0AH    ;Ввод строки
    LEA    DX,INPUTBUFER
    INT    21H
;===============================Найти разделитель===========================================
NEWS:
    MOV    DI,OLDSINDEX    ;Найти разделитель в предложении
S10:    MOV    CX,DELIMITERL    ;Цикл для всех разделителей
    LEA    SI,DELIMITER
S20:    LODSB
    CMP    AL,[DI]
    JE    NEWE
    LOOP    S20
    INC    DI    ;Следующий символ в строке
    JMP    S10
;=================================Сравнить слова=============================================
NEWE:
    ;DI указывает на разделитель после слова. OLDSINDEX - начало слова.
    PUSH    DI
    MOV    CX,DI
    SUB    CX,OLDSINDEX    ;CX - длина слова из текста
    MOV    BX,MASSINDEX
    CMP    CL,MASSL[BX]    ;Сравнить с длиной элемента
    JNE    NEXT    ;Если не равно то след. элем.
    
    MOV    DI,OLDSINDEX    ;Если ровно, то сравнить слова
    SHL    BX,1
    MOV    SI,MASSADR[BX]    ;MASSADR[BX*2]
    CLD
    REPE CMPSB
    JNE    NEXT    ;Если не равны, то след. элем.
            ;Если равны, то удалить

;====================================Удалить===============================================
    ;DI указывает на разделитель после слова. OLDSINDEX - начало слова.
    MOV    CX,DI    ;Заменить "*"
    SUB    CX,OLDSINDEX
    MOV    DI,OLDSINDEX
    MOV    AL,'*'
    CLD
    REP STOSB
;======================================Конец цикла=========================================
NEXT:    POP    DI
    INC    MASSINDEX    ;Следующий элемент массива
    MOV    AX,MASSLE
    CMP    AX,MASSINDEX    ;Если прошли все элементы,
    JNE    NEWE

    MOV    AL,LEN    ; то следующее слово в строке
    XOR    AH,AH
    ADD    AX,OFFSET STRIN
    CMP    AX,DI    ;Если строка закончилась
    JE    EXIT    ; то выход

    INC    DI
    MOV    OLDSINDEX,DI
    MOV    MASSINDEX,0
    JMP    NEWS
;==================================Вывод на экран и выход================================
EXIT:    MOV    BL,LEN    ;В конце строки поставить "$"
    XOR    BH,BH
    ADD    BX,OFFSET STRIN
    MOV    BYTE PTR [BX],'$'
    
    MOV    AH,09H    ;Перевод строки на дисплее
    LEA    DX,NEWLINE
    INT    21H
    
    LEA    DX,STRIN    ;Вывод результата
    INT    21H
    
    LEA    DX,NEWLINE    ;Перевод строки на дисплее
    INT    21H

    MOV    AX,4C00H    ;Выход
    INT    21H
    END    MAIN


Элементы данных, помеченыые ";*" изменять не рекомендуется. Программа работает так:
1)запрашивает ввод с клавиатуры строки,
2)запрещенные слова заменяет на звездочки.
3) выводит на экран результат

Запрещенные слова указаны в массиве MASS, их количество в переменной MASSLE, их длины в массиве MASSL, их адреса в массиве MASSADR.
В переменной DELIMITER указаны символы, которые считаются разделителями слов в предложении.

Добавлено через 2 минуты и 33 секунды
П. С. У этой программы есть минус: она чувствительна к регистру. Т.е. слово QWERTY будет заменено на звездочки, а Qwerty - нет.

Автор: octopus 8.11.2010, 19:26
)) Все именно так)) Спасибо огромное. реализация...ммм...потрясная) я-то хотела кучу процедур делать, да все никак подступиться не могла...Спасибо!
один только вопрос. 0DH, 0AH это ж новая строка. а по нажатию ентера она вводится в программу, если так можно выразится. т.е. эта программа расчитана для работы с файлами? или я чего-то не понимаю?

Еще раз спасибо. Просто спасли!))

Автор: iff 8.11.2010, 21:04
Цитата(octopus @  8.11.2010,  19:26 Найти цитируемый пост)
один только вопрос. 0DH, 0AH это ж новая строка.

Вы имеете ввиду что выводится 0DH, 0AH перед выводом результата и после него?
Да, это перевод строки. На экране. Когда мы воводим 0DH, 0AH курсор переходит на начало следующей строки.

Автор: octopus 9.11.2010, 21:11
)) Спасибо, не сразу поняла.
Я, как порядочная, хотела сама удаление организовать, да видно не судьба. Вот то, что у меня получилось. Тут есть ошибки, но предыдущие варианты либо циклились, либо толку от них не было... 
Код

;====================================Удалить===============================================
 ;DI указывает на разделитель после слова. OLDSINDEX - начало слова.
 ; DI - адрес смещения строки-источика, надо бы его в СИ
 ; в DI надо бы адрес смещения строки-приемника, т.е. DEST, (DEST db 255 dub(?))
 ; в СХ длина пересылаемого элемента строки.
 push CX
 mov DI, DESTPOS
 mov SI, DI
 mov CX, LEN  ; CX - length of STRIN
 sub DI, offset STRIN 
 add DI,2
 sub CX, DI
 
 rep MOVS DEST, STRIN 
 pop CX
 

Жду комментариев))) Спасибо.

ЗЫ еще вопрос. столкнулась с проблемой: через командную строку все замечательно работает, а вот через эмулятор(emu8086 4.00b7) никакого эффекта. с чем это может быть связано?

Автор: iff 10.11.2010, 19:04
Цитата(octopus @  9.11.2010,  21:11 Найти цитируемый пост)
через командную строку все замечательно работает, а вот через эмулятор(emu8086 4.00b7) никакого эффекта.

Значит в эмуляторе ошибка.

Цитата(octopus @  9.11.2010,  21:11 Найти цитируемый пост)
Я, как порядочная, хотела сама удаление организовать, да видно не судьба.

Вы хотите именно удалить? По-мойму горазду лучше (и не потому что проще smile ) не удалять, а заменять звездочками. Потому, что если из предложения бесследно выкинуть слово, то смысл самого предложения может потеряться, а вот если заменить его звездочками, или к примеру на его места поставить значок "<...>", тогда читающий поймет, что здесь пропущено слово, и тогда смысл предложения не разрушится.
Например, вы ввели в программу: "Несколько лет тому назад в одном из своих поместий жил старинный русской барин, Кирила Петрович Троекуров." А запрещенным словом пусть будет "жил". Если просто удалять запрещенные слова, то получится: "Несколько лет тому назад в одном из своих поместий старинный русской барин, Кирила Петрович Троекуров.", а если заменять звездочками, то получится "Несколько лет тому назад в одном из своих поместий *** старинный русской барин, Кирила Петрович Троекуров." Согласитесь, второй случай читать легче.

Автор: octopus 10.11.2010, 20:28
Так-то оно так. Но если подходить к лабе с этой стороны, то пусть это будет фильтр сообщений в чате, где некоторые могут позволить себе лексические вольности(а в массиве как раз эти вольности и содержатся))) тогда удаление вполне оправданно, особенно если публика чувствительная...
По правде говоря, задание состоит в том, чтобы УДАЛИТЬ запрещенные слова. Как видите, мне не удается это сделать самостоятельно((( 
А именно, почему в 9 строке компилятор выдает ошибку? в предыдущем блоке была такая же по смыслу операция...

Автор: iff 10.11.2010, 22:07
1) ошибку выдает из-за того что CX - слово, а LEN - байт.
2) 
Цитата(octopus @  10.11.2010,  20:28 Найти цитируемый пост)
 Но если подходить к лабе с этой стороны, то пусть это будет фильтр сообщений в чате, где некоторые могут позволить себе лексические вольности(а в массиве как раз эти вольности и содержатся))) тогда удаление вполне оправданно, особенно если публика чувствительная...

в данном случае удалить и "замазать" (заменить на символ "*") - это синонимы.

Но если хотите все таки сделать так что слово имменно бесследно исчезает из текста, то вот иллюстация:
http://www.radikal.ru
Это строка длинной 7 которая начинается со смещения 0; а нужно удалить подстроку длинной 2, которая начинается со смещения 2
Мы видим, что при использовании reb movsb, мы должны:
 а) инициализировать SI как смещение основной строки+смещение удаляемой подстроки+длина подстроки.
в данном случае 0+2+2=4.
 б) DI инициализировать как адрес начала удаляемой подстроки (в данном случае 2)
 в) в CX поместить смещение основной строки+длина основной строки-смещение удаляемой подстроки-длина удаляемой подстроки. В данном случае 0+7-2-2=3.
 г) незабудте переменную LEN уменьшить на длину удаляемой подстроки.

Автор: octopus 16.11.2010, 20:28
Спасибо!!

Автор: octopus 30.11.2010, 22:46
Да! На всякий случай, для тех, кому вдруг понадобится именно удаление!
этот кусок кода удаляет слово вместе с пробелами после него. 
Код

;====================================Удалить===============================================
    ;DI указывает на разделитель после слова. OLDSINDEX - начало слова.
;++++++++++++++++++++++++++++++++++++++++++++++=
push ax
space:
 mov ax, [di]
 cmp al, 32
 jne continue
 inc di
 jmp space
continue:
;++++++++++++++++++++++++++++++++++++++++++++++=

    mov    CX,DI            
    sub    CX,OLDSINDEX
   
    mov AX, CX               ; в АХ длина слова с пробелами

    lea CX, STRIN
    mov DI, OLDSINDEX
    sub DI, CX                ;  в ДИ смещение начала слова относительно начала предложения
  
    add di, ax                 ; смещение конца слова относительно предложения
    xor cx, cx
    mov cl, STRIN[1]       ; длина предложения
    sub cx, di                  ; длина оставшейся части предложения
    INC cx
    mov di, OLDSINDEX  ; абсолютное смещение начала слова
    
    push si      
    mov si, di                ;
    add si, ax               ; абсолютное смещение конца слова

    cld
    rep movsb
    
    pop si
    sub len, al              ; уменьшение количества символов в предложении
    pop ax
    mov OLDSINDEX, offset STRIN
    pop di
    mov di, OLDSINDEX
    jmp news


Добавлено через 29 секунд
может, не самая лучшая реализация, но я старалась)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)