Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для 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) ;
<< Назад В начало Далее >> |
|