Вопрос № 181458: Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующий вопрос: "Работа с файлами.Пользователь вводит с клавиатуры имя файла с текстом и имя создаваемого файла, в который будет помещен результат. Слова в строке могут быть разделены ...
Вопрос № 181458:
Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующий вопрос: "Работа с файлами.Пользователь вводит с клавиатуры имя файла с текстом и имя создаваемого файла, в который будет помещен результат. Слова в строке могут быть разделены пробелами и знаками препинания. Отсортировать строки файла по длинам" Тип памяти любой. Написание Tasm. (32 бита). (работа внутри тасма. тоесть через ctrl+f8)
Отправлен: 19.12.2010, 20:13
Вопрос задал: Ирина (Посетитель)
Всего ответов: 1 Страница вопроса »
Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, Ирина ! Вот Вам программа, которая сортирует указанный файл (< 64к)
Код:
;Пользователь вводит с клавиатуры имя файла с текстом
и имя создаваемого файла, ;в который будет помещен результат. Слова в строке могут быть разделены пробелами ;и знаками препинания. Отсортировать строки файла по длинам .model tiny .code .startup ;Определим место для данных за программой ;Для этого сначала ограничим стек 100h и разместим его сразу программой lea ax, last ;последний исползованный адрес and ax, 0fffeh ;сделаем кратным 2 add ax, 100h ;добавим место под стек mov s
p, ax ;вершина стека ;Теперь определим сегмент данных add ax, 0fh ;чтобы выровнять с избытком до параграфа (10h) shr ax, 4 ;длина программы+стека в параграфах mov cx, ds ;сегмент программы add ax, cx ;ax - сегмент за стеком - для данных mov segData, ax ;сораним ;и сегмент индексов add ax, 1000h ;размер сегмента данных - 64к mov segIdx, ax ;за ним разместим сегмент индексов
lea dx, sEnterIn ;строка приглашения ввести имя входного файла call GetName ;вводим
имя входного файла, результат - в dx jc Finish ;если пустая строка, то выходим
mov ax, 3d00h ;открываем на чтение int 21h jc OpenError ;не найдено - выводим сообщение и выходим mov bx, ax ;handle файла push ds ;сохраним сегмент данных программы mov ax, segData mov ds, ax ;сегмент данных файла xor dx, dx ;начальный адрес mov cx, 0fffdh ;максимальная возможная длина ; (2 байта резерва на возможный до
бавочный ; последний eol) mov ah, 3fh ;функция чтения int 21h jc ReadError ;если ошибка, то выводим сообщение и выходим mov si, ax ;длина файла cmp word ptr [si-2], 0a0dh ;проверим, есть ли в конце код конца строки je EolFound ;есть, ну и отлично mov word ptr [si], 0a0dh ;добавим 0d0a add ax, 2 ;и увеличим длину на 2 EolFound: pop ds ;восстановим сегмент данных программы mov FileLen, ax ;сохраним длину файла mov ah, 3eh ;закрываем файл int 21h
call FormIdx ;Сформируем
индексы в сегменте индексов
call Sort ;Отсортируем индексы
lea dx, sEnterOut ;строка приглашения ввести имя выходного файла call GetName ;вводим имя выходного файла, результат - в dx jc Finish ;если пустая строка, то выходим
mov ah, 3ch ;создаем выходной файл xor cx, cx ;без атрибутов int 21h jc CreateError ;ошибка - на выход mov bx, ax ;handle
call FormOut
;выводим в отсортированном порядке pushf mov ah, 3eh ;закрываем файл int 21h popf jc WriteError
Finish: ;все сделано... lea dx, sPress ;выведем приглашение нажать на любую клавишу mov ah, 9 int 21h
mov ah, 0 ;ждем клавишу int 16h
mov ax, 4c00h int 21h ;выход в ДОС
;Сообщения об ошибках OpenError: lea dx, sOpenError jmp PrintStr ReadError: pop ds ;т.к. регистр ds был в стеке lea dx, sReadError jmp PrintStr CreateError: lea dx,
sCreateError jmp PrintStr WriteError: lea dx, sWriteError PrintStr: ;выводим сообщение mov ah, 9 int 21h jmp Finish
GetName proc ;Вводим строку с именем mov ah, 9 int 21h ;приглашение на ввод имени входного файла
mov bNum, 80 ;максимальный размер буфера для ввода строки lea dx, bNum mov ah, 0ah int 21h ;вводим строку
;отсечем лидирующие пробелы lea si, sName
;введенная строка GNStart: lodsb ;очередной символ cmp al, ' ' je GNStart ;пробелы пропускаем cmp al, 0d
h je GNError ;если пустая строка или пробелы, то взведем FC lea dx, [si-1] ;есть начало строки, имени файла GNEnd: ;найдем конец имени - пробел или код 0dh lodsb ;очередной символ cmp al, 0dh je EndFound ;конец строки cmp al, ' ' ;и пробел - нашли конец имени jne GNEnd ;иначе продолжаем искать EndFound: mov byte ptr [si-1], 0 ;вставим 0 в конце имени clc ;есть имя файла ret GNError: stc ;пустая строка ret GetName endp
FormIdx proc ;формирование
массива индексов push ds es ;будем менять сегментные регистры mov cx, FileLen ;длина данных mov es, segData ;сегмент данных mov ds, segIdx ;сегмент индексов xor di, di ;адрес в сегменте данных xor si, si ;адрес в сегменте индексов mov al, 0dh ;будем искать код 0dh FormIdxLoop: ;цикл по всем символам jcxz FormIdxRet ;cx=0 в конце данных mov bx, di ;запомним начало строки repne s
casb ;ищем конец строки, который есть обязательно ; (мы в случае необходимости добавили в конец 0d0a) mov dx, di ;адрес конца строки + 1 sub dx, bx ;длина строки + 1 dec dx ;ровно длина строки mov [si], bx ;сохраняем адрес начала строки mov [si+2], dx ;и длину строки (без 0d0a) add si, 4 ;на следующую запись индекса inc di ;пройдем код 0ah dec cx ;уменьшим для него счетчик символов jmp FormIdxLoop ;пока не пройдем все данные файла FormIdxRet: shr si,
2 ;si - число строк файла! pop es ds mov Rows, si ;запомним число строк файла ret FormIdx endp
cmp cx, 2 ;0 и 1 нет смысла сортировать jb SortRet dec cx ;число сравнений xor si, si ;адрес индекса SortLoop: ;цикл по поиску очередного минимального lea di, [si+4]
;начинаем со следующего push cx ;сохраним счетчик mov ax, [si+2] ;текущий минимальный по адресу [si] SearchMinLoop: ;цикл по всем последующим ;сравниваем текущий со всеми последующими cmp ax, [di+2] ;если текущий минимальный <= последующего, jle SortNext ; то обходим обмен ;меняем местами элементы mov ax, [si] ;меняем местами адреса строк xchg ax, [di] mov [si], ax mov ax, [si+2] ;меняем местами длины строк xchg ax, [di+2] mov [si+2], ax ;по адресу
[si+2] и в ax новая минимальная длина SortNext: add di, 4 ;на следующий последующий loop SearchMinLoop add si, 4 ;на следующий текущий pop cx ;восстановим счетчик сравнений loop SortLoop
SortRet: pop ds ret Sort endp
FormOut proc ;выводим в файл все строки в отсорт виде push ds es mov cx, Rows ;число строк mov es, segIdx ;сегмент индексов mov ds, segData ;сегмент данных xor si, si ;адрес
индекса WriteLinesLoop: ;по всем строкам push cx ;сохраним счетчик строк mov dx, es:[si] ;адрес строки mov cx, es:[si+2] ;длина строки add cx, 2 ;+ 2 байта 0d0a mov ah, 40h int 21h ;пишем в файл pop cx ;воостановим счетчик строк jc FormOutRet ;ксли ошибка, то FC = 1 add si, 4 ;на след индекс loop WriteLinesLoop clc ;все ок FormOutRet: pop es ds ret FormOut endp
.data sEnterIn db 'Enter input file name: $' sEnterOut db 0ah,'Enter
output file name: $' sPress db 0ah,'Press any key$' sOpenError db 0ah,'Open Error',0dh,'$' sReadError db 0ah,'Read Error',0dh,'$' sCreateError db 0ah,'Create Error',0dh,'$' sWriteError db 0ah,'Write Error',0dh,'$'
.data? segData dw ? ;сегмент данных segIdx dw ? ;сегмент индексов FileLen dw ? ;длина файла Rows dw ? ;число строк <
br>;буфер для ввода числовой строки (для функции 0ah) bNum db ? ;максимальный размер буфера bCount db ? ;реальный размер строки sName db 80 dup (?) ;сама строка
Last label byte ;последний использованный адрес
end
----- Люби своего ближнего, как самого себя
Ответ отправил: Лысков Игорь Витальевич (Старший модератор)
Ответ отправлен: 26.12.2010, 00:55
Номер ответа: 265079 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 265079
на номер 1151 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.