ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 15

Глава 13. Модуль Strings
В Турбо Паскале для Windows вводится поддержка нового класса символьных строк, которые называются строками, завершающимися нулем. Благодаря расширенному синтаксису Турбо Паскаля и модулю Strings ваши программы могут использовать строки с завершающим нуле
м - формат, необходимый для интерфейса прикладных программ Windows.
           Что такое строка с завершающим нулем?

     В Турбо Паскале строки обычного типа хранятся как байт длины, за которым следует последовательность символов. Максимальная длина строки в Турбо Паскале равна 255 символам. Таким образом, строка Турбо Паскаля занимает от 1 до 256 байт памяти. 
     Строки с завершающим нулем не содержат байта длины. Вместо этого они состоят из последовательности ненулевых символов, за которыми следует символ NULL (#0). Никаких граничений на длину строк с завершающим нулем не накладывается, но 16-разрядная архи
тектура DOS и Windows ограничивает их размер 65535 символами. 
     Вы можете использовать для копирования строки Турбо Паскаля в строку с завершающим нулем подпрограмму StrPCopy, а для преобразования строки с завершающим нулем в строку Турбо Паскаля - подпрограмму StrPas. 
          Использование строк с завершающим нулем

     Строки с завершающим нулем хранятся в виде символьных массивов с нулевой базой (начинающихся с 0) с индексом целого типа, то есть в виде массива: 
     array[0..X] of Char;
 где X - положительное ненулевое целое число. Такие массивы называются символьными массивами с нулевой базой. Приведем некоторые примеры описаний символьных массивов с нулевой базой, которые могут использоваться для хранения завершающихся нулем строк. 
     type
        TIdentifier = array[0..15] of Char;
        TFileName   = array[0..79] of Char;
        TMemoText   = array[0..1023] of Char;

     Более всего строки Турбо Паскаля и строки с завершающим нулем отличаются интенсивностью использования указателей. Турбо Паскаль для Windows выполняет операции с этими указателями, используя набор правил расширенного синтаксиса. Кроме того, в Турбо П
аскале имеется новый встроенный тип PChar, который представляет собой указатель на строку с завершающим нулем. В модуле System тип PChar определяется следующим образом: 
     type PChar = ^Char;

     Правилами расширенного синтаксиса управляет директива компилятора $X. В состоянии {$X+} (по умолчанию) расширенный синтаксис разрешен. Правила расширенного синтаксиса описываются в следующих разделах. 
         Символьные указатели и строковые литералы

     При разрешении расширенного синтаксиса строковый литерал совместим по присваиванию с типом PChar. Это означает, что переменной типа PChar можно присвоить строковый литерал. Например: 
     var
        P: PChar;
        .
        .
     begin
        P := 'Привет...';
     end;

     В результате такого присваивания указатель указывает на область памяти, содержащую строку с завершающим нулем, являющуюся копией строкового литерала. Компилятор записывает строковые литералы в сегмент данных, аналогично описанию "скрытых" типизованн
ых констант: 
     const
        TempString: array[0..14] of Char = 'Привет...'#0;
     var
        P: PChar;
        .
        .
     begin
        P := @TempString;
     end;

     Когда соответствующие формальные параметры имеют тип Char, строковые литералы вы можете использовать, как фактические параметры при вызовах процедур и функций. Например, если имеется процедура с описанием: 
     procedure PrintStr(Str: PChar);
     PrintStr(#10#13);

     Аналогично тому, как это происходит при присваивании, компилятор генерирует строку с завершающим нулем, представляющую собой копию литеральной строки в сегменте данных, и передает указатель на эту область памяти в параметре Str процедуры PrintStr. 
     Наконец, типизованная константа типа PChar может инициализироваться строковой константой. Это справедливо также для структурных типов, таких как массивы PChar и записи, а также объекты PChar. 
     const
        Message: PChar = 'Program terminated';
        Prompt: PChar = 'Enter values: ';
        Digits; array [0..9] of PChar = {
         'Zero', 'One', 'Two', 'Three', 'Four', 'Five',
         'Six', 'Seven', Eight', 'Nine'};

         Символьные указатели и символьные массивы

     Если вы с помощью директивы $X разрешаете расширенный синтаксис, то символьный массив с нулевой базой совместим с типом PChar. Это означает, что там, где предполагается использование типа PChar, может использоваться символьный массив с нулевой базой
. Когда символьный массив используется вместо значения PChar, компилятор преобразует символьный массив в указатель-константу, значение которой соответствует адресу первого элемента массива. 
     var
        A: array[0..63] of Char;
        P: PChar;
        .
        .
     begin
        P := A;
        PrintStr(A);
        PrintStr(P);
     end;

     Благоадря оператору присваивания P теперь указывает на первый элемент массива A, поэтому PrintStr вызывается дважды с одним и тем же значением. Вы можете инициализировать типизованную константу, имеющую тип символьного массива с нулевой базой, с пом
ощью строкового литерала, имеющего меньшую длину, чем размер массива. Оставшиеся символы устанавливаются в значение NULL (#0), и массив будет содержать строку с завершающим нулем. 
     type
        TFileName = array[0..79] of Char;
     const
        FileNameBuf: TfileName = 'TEST.PAS';
        FileNamePtr: PCahr = FileNameBuf;

           Индексирование символьного указателя

     Так как символьный массив с нулевой базой совместим с символьным указателем, символьный указатель можно индексировать аналогично символьному массиву с нулевой базой. 
     var
        A: array[0..63] of Char;
        P: PChar;
        Ch: Char;
        .
        .
     begin
        P := A;
        Ch := A[5];
        Ch := P[5];
     end;

     Оба последних присваивания присваивают Ch значение, содержащееся в шестом символе-элементе A. 
     При индексировании символьного указателя индекс задает беззнаковое смещение, которое добавляется к указателю перед его разыменованием. Таким образом, P[0] эквивалентно P^ и задает символ, на который указывает P. P[1] задает символ справа от того, на
 который указывает P, P[2] задает следующий символ и т.д. Для целей индексирования PChar ведет себя таким образом, как если бы он описывался: 
     type
       TCharArray = array[0..65535] of Char;
       Pchar = ^TCharArray;

     Компилятор при индексировании символьного указателя не выполняет проверку диапазона, так как у него нет информации о типе, по которой можно определить максимальную длину строки с завершающим нулем, на которую указывает символьный указатель.
     Показанная ниже функция StrUpper иллюстрирует использование символьного указателя для преобразования строки с завершающим нулем в верхний регистр. 
     function StrUpper(Srt: Pchar): Pchar;
     var
        I: Word;
     begin
        I := 0;
        while Str[I] <> #0 do
        begin
          Str[I] := UpCase(Str[I]);
          Inc(I);
        end;
        StrUpper := Str;
     end;

     Обратите внимание, что StrUppper - это функция, а не процедура, и что она всегда возвращает значение, которое передавалось ей в качестве параметра. Так как расширенный синтаксис допускает игнорирование результата функции, StrUpper может интерпретиро
ваться, как процедура: 
     StrUpper(A);
     PrintStr(A);

     Однако, StrUpper всегда возвращает передаваемое ей значение, приведенные выше операторы можно скомбинировать в один: 
     PrintStr(StrUpper(A));

     Вложенные вызовы функций работы со строками с завершающим нулем могут оказаться очень удобными, когда вы хотите указать определенную взаимосвязь между последовательными операциями со строками. 
            Операции с символьными указателями

     Расширенный синтаксис Турбо Паскаля позволяет использовать для работы с символьными указателями новые операции. Для увеличения или уменьшения смещения в значении указателя можно использовать операции плюс (+) и минус (-). Операцию минус (-) можно ис
пользовать для вычисления расстояния (разности смещений) между двумя символьными указателями. Прпедположим, что P и Q представляют собой значения тип PChar, а I - значение типа Word. Тогда допустимы следующие конструкции: 
     P + I     I прибавляется к смещению P
     I + P     I прибавляется к смещению P
     P - I     I вычитается из смещения P
     P - Q     Смещение Q вычитается из смещения P

     В операциях P + I и I + P I прибавляется к адресу, задаваемому P. При этом получается указатель, который указывает на I символов после P. В операции P - I I вычитается из адреса, задаваемого P, и получается указатель, указывающий на I символов до P.
 
     Операция P - Q вычисляет рассотояние между Q (младший адрес) и P (старший адрес). При этом возвращается результат типа Word, показывающий число символов между Q и P. Эта операция предполагает, что P и Q указывают на один и тот же массив символов. Ес
ли эти два указателя указывают на разные символьные массивы, то результат непредсказуем. 
     Стандартный синтаксис Турбо Паскаля позволяет при сравнении указателей определять только их равенство или неравенство. Расширенный синтаксис (разрешенный по директиве компилятора {$X+}) позволяет применять операции <, >, <= и <= к значениям PChar. З
аметим, однако, что при таких проверках предполагается, что два сравниваемых указателя указывают на один и тот же массив символов. По этой причине сравниваются только смещения указателей. Если два указателя указывают на различные символьные массивы, то р
езультат не определен. 
     var
        A, B: array[0..79] of Char;
        P, Q: PChar;
     begin
        P := A;                { P указывает на A[0] }
        Q := A + 5;            { Q указывает на A[5] }
        if P < Q then ...;     { допустимая проверка,
                                 результат - True }
        Q := B;                { Q указывает на B[0] }
        if P < Q then ...;     { результат не определен }
     end;

    Строки с завершающим нулем и стандартные процедуры

     Расширенный синтаксис Турбо Паскаля позволяет применять к символьным массивам с нулевой базой стантартные процедуры Read, ReadLn и Val, а к символьным массива с нулевой базой и символьным указателям - стандартные процедуры Write, WriteLn, Val, Assig
n и Rename. Более подробные описания этих процедур можно найти в Главе 24. 
               Использование модуля Strings

     Турбо Паскаль для Windows не содержит встроенных подпрограмм, предназначенных специально для обработки строк с завершающим нулем. Все такие функции вы можете найти в модуле Strings. Приведем краткое описание каждой функции. 
     Примечание: Более подробное описание функций можно найти в Главе 24 "Библиотека исполняющей системы". 
 ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
 Функция          Описание
 ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
 StrLen           Возвращает длину строки.

 StrEnd           Возвращает указатель на конец строки, то
                  есть указатель на завершающий строку
                  нулевой символ.

 StrMove          Перемещает блок символов из исходной
                  строки в целевую строку и возвращает
                  указатель на целевую строку. Два блока
                  могут перекрываться.

 StrCopy          Копирует исходную строку в целевую строку
                  и возвращает указатель на целевую строку.

 StrECopy         Копирует исходную строку в целевую строку
                  и возвращает указатель на конец целевой
                  строки.

 StrLCopy         Копирует заданное число символов из
                  исходной строки в целевую строку и
                  возвращает указатель на целевую строку.

 StrPCopy         Копирует строку Паскаля в строку с
                  завершающим нулем и возвращает указатель
                  на строку с завершающим нулем.

 StrCat           Присоединяет исходную строку к концу
                  целевой строки и возвращает указатель на
                  целевую строку.

 StrLCat          Присоединяет исходную строку к концу
                  целевой строки. При этом обеспечивается,
                  что длина результирующей строки не
                  превышает заданного максимума.
                  Возвращается указатель на
                  строку-результат.

 StrComp          Сравнивает две строки S1 и  S2.
                  Возвращает значение < 0, если S1 < S2,
                  равное 0, если S1 = S2 и > 0, если S1 >
                  S2.

 StrIComp         Сравнивает две строки без различия
                  регистра символов.

 StrLComp         Сравнивает две строки с заданной
                  максимальной длиной.

 StrLIComp        Сравнивает две строки с заданной
                  максимальной длиной без различия регистра
                  символов.

 StrPas           Преобразует строку с завершающим нулем в
                  строку Турбо Паскаля.

 StrPos           Возвращает указатель на первое вхождение
                  заданной подстроки в строке, или nil,
                  если подстрока в строке не содержится.

 StrRScan         Возвращает указатель на последнее
                  вхождение указанного символа в строку,
                  или nil, если символ в строке
                  отсутствует.

 StrScan          Возвращает указатель на первое
                  вхождение указанного символа в строку,
                  или nil, если символ в строке
                  отсутствует.

 StrUpper         Преобразует строку в верхний регистр и
                  возвращает указатель на нее.

 StrLower         Преобразует строку в нижний регистр и
                  возвращает указатель на нее.

 StrNew           Выделяет для строки память в динамически
                  распределяемой области.
 ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Приведем пример исходного кода, показывающий, как можно использовать некоторые функции обработки строк. Этот пример использован при разработке функции FileSplit в модуле WinDos. 
     { максимальные размеры компонентов имени файла }

     const
       fsPathName    = 79;            { имя маршрута }
       fsDirectory   = 67;            { имя каталога }
       fsFileName    = 8;             { имя файла }
       fsExtension   = 4;             { расширение имени файла }

     { флаги, возвращаемые FileSplit }

     const
            fcWildcards   = $0008     { трафаретные символы }
            fcDirectory   = $0004     { имя каталога }
            fcFileName    = $0002     { имя файла }
            fcExtension   = $0001     { расширение имени файла }

   { FileSplit разбивает имя файла,  заданное маршрутом,  на три }
   { компонента.  Dir  принимает  значение  диска  и  каталога с }
   { предшествующей и завершающей обратной  косой  чертой,  Name }
   { принимает  значение  имени  файла,  а  Ext  -  расширения с }
   { предшествующей  точкой.  Если  компонент   строки-параметра }
   { равен   NIL,   то   соответствующая   часть   маршрута   не }
   { записывается.  Если маршрут не содержит данного компонента, }
   { то    возвращаемая    строка   компонента   будет   пустой. }
   { Максимальные длины строк,  возвращаемых в Dir,  Name и Ext, }
   { определяются   битовыми  масками  fsDirectory,  fsFileName, }
   { fsExtension.  Возвращаемое  значение   представляет   собой }
   { комбинацию   битовых   масок   fсDirectory,   fсFileName  и }
   { fсExtension,  показывающую, какие компоненты присутствуют в }
   { маршруте.   Если  имя  и  расширение  содержат  трафаретные }
   { символы (* и ?), то в возвращаемом значении устанавливается }
   { флаг fcWildcards. }

     function FileSplit(Path, Dir, Name, Ext: PChar): Word;
     var
        DirLen, NameLEn, Flags: Word;
        NamePtr, ExtPtr: PChar;
     begin
        NamePtr := StrRScan(Path, '/');
        if NamePtr = nil then NamePtr := StrRScan(Path, ':');
        if NamePtr = nil then NamePtr := Path else Inc(NamePtr);
        ExtPtr := StrScan(NamePtr, '.');
        if ExtPtr = nil then ExtPtr := StrEnd(NamePtr);
        DirLen := NamePtr - Path;
        if DirLen > fsDirectory then DirLen := fsDirectory;
        NameLen := ExtPtr - NamePtr;
        if NameLen > fsFilename then NameLen := fsFileName;
        Flags := 0;
        if (StrScan(NamePtr, '?') <> nil) or
           (StrScan(NamePtr, '*') <> nil[) then
           Falgs := fcWildcards;
        if DirLen <> 0 then Flags := Flags or fcDirectory;
        if NameLen <> 0 then Flags := Flags or fcFilename;
        if ExtPtr[0] <> #0 then Flags := Flags or fcExtension;
        if Dir <> nil then StrLCopy(Dir, Path, DirLen);
        if Name <> nil then StrLCopy(Name, NamePtr, NameLen);
        if Ext <> nil then StrLCopy(Ext, ExtPtr, fsExtension);
        FileSplit := Flags:
     end;


Яндекс цитирования