Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Для выполнения сравнения нужно поместить в регистр AL СИМВОЛ пробела и командой scasb просматривать строку. Поскольку мы рассматриваем самый общий случай размещения слов и разделителей, то не исключен вариант, когда пробелов между словами будет несколько. Для корректной отработки такой ситуации служит команда:
cmp BYTE PTR [EDI],
которая передает управление на метку @next, пока встречается символ пробела. Если найден первый символ строки, не равный пробелу, произойдет переход на метку OincEDX, и содержимое счетчика слов увеличится на 1. Число итераций не превысит содержимого счетчика ЕСХ. При выходе из цикла loop регистр EDX содержит количество слов в строке. Это значение возвращается в регистре ЕАХ в основную программу.
В обработчике нажатия кнопки происходит инициализация строки si, вычисление ее размера lsi и вызов процедуры RetNumwords. Вычисленное значение lsi вместе с адресом строки передается процедуре в качестве параметров: lsl := StrLen(sl);
numWords := RetNumWords(si, lsl);
Еще одно замечание. В качестве разделителя слов может служить любой другой символ, например символ табуляции. В этом случае достаточно заменить символ пробела в соответствующих командах программы на нужный символ-разделитель.
Наш следующий пример связан с преобразованием и обработкой строк различного типа. Это одна из довольно сложных проблем, с которыми сталкивается программист при написании Delphi-приложений. Дело в том, что в Delphi многие функции обработки текстовых и символьных данных выполняются с использованием длинных строк (ANSI String), о которых было упомянуто ранее. Между тем, Windows в качестве стандарта использует строки с завершающим нулем. Следовательно, необходимо преобразовать длинную строку в строку с завершающим нулем.

Можно задать вопрос: а не будет ли проще работать напрямую с длинными строками без этих преобразований? Если только работать в Delphi и не использовать мощный арсенал функций WIN^API и ассемблера, то да. Но, скорее всего, такое ограничение не обрадует программиста, поскольку вряд ли более-менее серьезное приложение обойдется без подобного инструментария. Хотя разработчики Delphi сделали максимум возможного для совместимости этих строк, отличия все же остаются, поэтому приходится использовать определенные ухищрения для конвертации строк и обработки данных.
В качестве примера разработаем программу, в которой будет анализироваться строка, где разделителями слов являются символы пробела. Все такие символы заменим для наглядности на символ " + " . На главной форме приложения разместим два поля редактирования Edit, кнопку Button и две метки статического текста Label. Одно поле редактирования принимает исходную строку, а другое — выполняет вывод модифицированной строки. Исходный текст приложения приведен в листинге 6.35.
Листинг 6.35. Программа; выполняющая поиск и замену разделителей в строке определенным символом ' Л "

unit rcpas;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForml = class(TForm)
Editl : TEdit;
Labell : TLabel;
Edit2 : TEdit;
Label2 : TLabel;
Buttonl: TButton;
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Forml: TForml;
lensrc: Integer;
buf: PChar;
implementation
{$R *.dfm}
procedure ReplaceSpace(sx: PChar; stl: Integer); stdcaii;
asm i
push EDI
mov EDI, DWORD PTR sx
mov ЕСХ, DWORD PTR stl
eld
mov AL,
@next:
scasb
mov
jne @skip
BYTE PTR [EDI-1], ' + '
@skip:
loop @next
pop EDI
end;
procedure TForml.ButtonlClick(Sender: TObject);
begin
lensrc := Editl.GetTextLen;
Inc(lensrc);
GetMem(buf, lensrc) ;
Editl.GetTextBuf(buf, lensrc);
ReplaceSpace(buf, lensrc);
Edit2.Text := StrPas(buf);
FreeMem(buf, lensrc);

Строки в полях редактирования имеют тип ANSI String, а обрабатывать их
очень удобно, предварительно преобразовав в строки с завершающим нулем.
В нашем примере обработка строки с завершающим нулем выполняется
ассемблерной процедурой ReplaceSpace, которая принимает в качестве
параметров указатель на строку типа pchar и размер строки.
Предварительное преобразование длинной строки в строку с завершающим
нулем выполняется в основной программе:
lensrc := Editl.GetTextLen;
Inc(lensrc);
GetMem(buf, lensrc);
Editl.GetTextBuf(buf, lensrc);
end;
end.

Первое что мы делаем — это получаем размер длинной строки при помощи процедуры GetTextLen. Следующим оператором увеличиваем полученный размер на 1. Если мы планируем работать со строкой типа pchar (строка с завершающим нулем в Delphi), то это необходимо для резервирования места, где будет находиться символ окончания строки, т. е. 0.
Как правило, преобразование одного типа в другой выполняется с помещением исходного значения переменной в буфер памяти. Результат преобразования обычно помещается в эту же область памяти. Поэтому вызов GetMem выделяет буфер памяти для хранения строки размером lensrc. Наконец, GetTextBuf помещает строку из поля редактирования в буфер. После этого в области памяти buf будет находиться строка с завершающим нулем. Последующие преобразования ассемблерной процедурой ReplaceSpace выполняются уже над строкой типа PChar.

Проанализируем работу процедуры ReplaceSpace. Она принимает в качестве параметров адрес строки с завершающим нулем и ее размер. В начале процедуры загружаем адрес строки в регистр EDI, а ее размер — в регистр ЕСХ, который будем использовать в качестве счетчика цикла. Для организации поиска символа пробела воспользуемся знакомой нам командой scasb:
eld
mov AL, ' '
@next:
scasb
jne @skip

Установим флаг направления так, чтобы адрес инкрементировался в каждой итерации. Если символ пробела найден, то необходимо его заменить на " + " . Поскольку после выполнения команды scasb содержимое регистра EDI увеличилось на 1, то записать символ " + " необходимо в ячейку памяти с адресом [EDI- 1 ]:
mov BYTE PTR [EDI-1], '+'

После замены всех пробелов нам необходимо вывести результат в поле редактирования Edit2. Для этого выполним преобразование строки типа PChar в ANSI String и присвоим полученный результат свойству Text компонента Edit2. Это выполняет оператор:
Edit2.Text := StrPas(buf);

И, наконец, последней командой обработчика нажатия кнопки освободим буфер памяти:
FreeMem(buf, lensrc) ;


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru