Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СРЕДСТВА ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ.doc
Скачиваний:
13
Добавлен:
02.05.2019
Размер:
2.13 Mб
Скачать

7.3. Строки

Для обработки текстов в Object Pascal используются следующие типы:

  • короткая строка shortString или string [n] , где n <= 255;

  • длинная строка string;

  • широкая строка WideString;

  • нуль-терминальная строка pchar.

Общим для этих типов является то, что каждая строка трактуется как одномерный массив символов, количество символов в котором может меняться в работающей программе: для string [n] длина строки меняется от 0 до n, для string и pchar - от 0 до 2 Гбайт.

В стандартном Паскале используются только короткие строки String [n] . В памяти такой строке выделяется n+i байт, первый байт содержит текущую длину строки, а сами символы располагаются начиная со 2-го по счету байта. Поскольку для длины строки в этом случае отводится один байт, максимальная длина короткой строки не может превышать 255 символов. Для объявления короткой строки максимальной длины предназначен стандартный тип ShortString (эквивалент String[255]).

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

В 32-разрядных версиях Delphi введен новый тип string, сочетающий в себе удобства обоих типов. При работе с этим типом память выделяется по мере надобности (динамически) и ограничена имеющейся в распоряжении программы доступной памятью. Замечу, что в Delphi 1 тип string эквивалентен String [2 55], т. е. определяет короткую строку максимально возможной длины.

Для совместимости с компонентами, основывающимися на OLE-технологии, в Delphi 32 введены также широкие строки, объявляемые стандартным типом wideString. По своим свойствам они идентичны длинным строкам string, но отличаются от них тем, что для представления каждого символа используются не один, а два байта.

Примеры объявлений строковых типов:

var

ssS: String[250];// Короткая строка длиной до 250 символов

ssMax: ShortString;// Короткая строка длиной до 255 символов

stS: String; // Длинная строка

swS: WideString;// Широкая строка

pcS: PChar; // Ссылка на нуль-терминальную строку

acS: array [0..1000] of Char; // Нуль-терминальная строка

// длиной до 1000 символов

При объявлении переменной sss компилятор выделит для ее размещения 250 + 1 = 251 байт и поместит в первый байт 0 - текущую длину строки. При выполнении такого фрагмента программы:

procedure TfmExample.bbRunClick(Sender: TObject);

var

ssS: String[250];

begin

ssS :='Строка символов';

ssS[6] := 'и'; // Символы в строке нумеруются, начиная с 1 IbOutput.Caption := ssS; // Выводится “Строки символов”

end;

сначала в переменную ssS будет помещена цепочка символов строка символов, причем 1-й байт получит значение 15 (количество символов в строке). После выполнения второго оператора символ с индексом б (индексация байтов начинается с 0, но, поскольку первый байт содержит текущую длину, первый символ в строке имеет индекс 1) будет заменен на “и”, и в переменной окажется цепочка строки символов.

Совершенно другим будет механизм работы с памятью при объявлении длинной строки sts: компилятор выделит для переменной 4 байта, достаточные для размещения номера той ячейки памяти, начиная с которой будет фактически располагаться символьная строка. Говорят, что sts ссылается на строку. Такого рода переменные-ссылки называются указателями и обсуждаются в гл. 9. При выполнении первого оператора такого обработчика:

procedure TfmExample.bbRunClick(Sender: TObject);

var

stS, stSS: String;

begin

stS :='Строка символов';

stSS := stS;

stS := 'Это - '+stS;

stS[7] := ' c' ; // Символы в строке нумеруются, начиная с 1 IbOutput.Caption := stS; //Выводится “Это - строка символов”

end;

программа (а не компилятор!) определит длину цепочки символов Строка символов, обратится к ядру перационной системы (ОС) с требованием выделить для нее участок памяти длиной 15+5=20 байт, поместит в переменную sts номер первого выделенного байта [На самом деле в stS запоминается дескриптор выделенного участка памяти, см. гл. 9.] и, начиная с него, разместит в этом участке цепочку символов, завершив ее терминальным нулем и 4-байтным счетчиком ссылок. Такое размещение на этапе прогона программы называется динамическим, в то время как размещение на этапе компиляции - статическим. Счетчик ссылок играет важную роль в механизме работы с памятью. С его помощью реализуется “кэширование” памяти: при выполнении оператора

stSS := stS;

память для размещения значения переменной stSS не выделяется, в переменную stSS помещается содержимое указателя sts, а счетчик ссылок в связанной с ним памяти увеличивается на единицу. Таким образом, оба указателя будут ссылаться на одну и ту же область памяти, счетчик ссылок которой будет содержать значение 2. При выполнении оператора

stS := 'Это - '+stS;

счетчик ссылок уменьшается на единицу, выделяется новая область памяти длиной 2 о + б = 2 б байт, указатель на эту область помещается в stS, а в саму память переписывается цепочка символов Это -строка символов, терминальный ноль и содержащий единицу счетчик ссылок. Теперь переменные stS и stss будут ссылаться на разные участки памяти, счетчики ссылок которых будут содержать по единице. Выделенная для размещения строки String область памяти освобождается, если ее счетчик ссылок стал равен нулю.

Похожим образом осуществляется работа с памятью при объявлении переменной pcs типа pchar: компилятор считает эту переменную указателем и выделит для нее 4 байта:

 

procedure TfmExample.bbRunClick(Sender: TObject);

var

pcS: PChar;

begin

pcS :='Строка символов';

pcS[5] := 'и';{Символы в нуль-строке нумеруются,начиная с 0}

IbOutput.Caption := pcS; // Выводится “Строки символов”

end;

Программа потребует от ОС 15 + 1 = 16 байт, разместит в памяти цепочку символов и завершающий ее терминальный 0 и поместит адрес выделенного участка памяти в pcs.

В стандартном паскале, при обращении к области памяти, на которую ссылается указатель , требуется за именем указателя ставить специальный символ .“^”. В Object Раsса1 интенсивно используется динамическая, память, и поэтому, это жесткое требование смягчено: в большинстве случаев (и при обращении к типу pchar в том числе) символ "^" ставить не следует.

И, наконец, последнее объявление acs как массива символов. В Object Pascal считается совместимым с pchar одномерный массив символов с нулевой нижней границей. В отличие от pcs память для такой переменной выделяется статически (в нашем примере компилятор выделит в сегменте данных для переменной acs 1001 байт).

Для размещения в acs нуль-терминальной цепочки символов используется процедура strcopy:

procedure' TfmExample.bbRunClick(Sender: TObject) ;

var

acS: array [0..1000] of Char;

begin

StrCopy(acS,'Строка символов') ;

acS[5] := 'и';{ Символы в нуль-строке нумеруются,начиная с 0}

lbOutput.Caption := acS; // Выводится “Строки символов”

end;

Необходимость в нуль-терминальных строках возникает только при прямом обращении к API-функциям ОС. При работе с компонентами Delphi в основном используются более удобные длинные строки, которые рассматриваются в п. 7.3.1.

И несколько слов о широких строках, 32-разрядные версии Windows используют три сорта символов: однобайтный символ ANSI, двухбайтный символ и символ Unicode. Однобайтный символ связан с одним из 256 возможных значений, которые трактуются в зависимости от установленной в Windows национальной страницы (для размещения кириллицы используется страница 1251). 256 символов вполне достаточны для отображения национального алфавита любого европейского языка. Для отображения алфавитов некоторых азиатских языков этого недостаточно. В этом случае используется двухбайтный символ, в котором младший байт обычно кодируется семибитным ASCII-кодом, а старший указывает, как должен трактоваться этот код (каким символом он будет изображаться в документе или на экране). Символ Unicode в памяти занимает одно слово, которое имеет 65536 возможных значений. Специальная международная комиссия по Unicode выработала соглашение, позволяющее с помощью этого кода представить все символы всех языков мира. Двухбайтные символы и символы Unicode объявляются стандартным типом widecnar, а составленные из них строки - типом widestring. Все Windows-программы, использующие OLE-технологию обмена строками, должны кодировать символы в соответствии с Unicode.

7.3.1. Типы String и ShortString

Несмотря на разницу во внутреннем представлении, короткие строки ShortString и длинные строки string имеют для программиста одинаковые свойства.

Текущую длину строки можно получить с помощью функции Length. Например, следующий оператор уничтожает все ведомые (хвостовые) пробелы:

while (Length(stS) о 0) and (stS[Length(stS)] = ' ') do

SetLentgh(stS, Length (stS) - 1);

В этом примере стандартная процедура setLength устанавливает новую длину строки. К строкам можно применять операцию “+” -сцепление, например:

stS := 'а' + 'b'; // stS содержит "ab"

stS := stS + 'с'; // stS содержит "abc"

Если длина сцепленной строки превысит максимально допустимую длину N короткой строки, то “лишние” символы отбрасываются. Следующая программа, например, выведет символ “I”:

Procedure TfmExamlpe.bbRunClick(Sender: TObject);

var

ssS: String[1];

begin

ssS := '123';

IbOutput := ssS;

end;

Операции отношения =, <>, >, <, >=, <= выполняются над двумя строками посимвольно, слева направо с учетом внутренней кодировки символов. Если одна строка меньше другой по длине, недостающие символы короткой строки заменяются значением #о.

Следующие операции отношения дадут значение True:

'''' < '.'

'А' > '1'

'Object' < ' Object Pascal'

'Пас' > 'Pascal'

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

Таблица 7.7. Процедуры и функции для работы со строками

Function AnsiLowerCase(const S: String): String;

Возвращает исходную строку S, в которой все заглавные буквы заменены на строчные в соответствии с национальной кодировкой Windows (т. е. с учетом кириллицы)

Function AnsiUpperCase(const S: String): String;

Возвращает исходную строку s, в которой все строчные буквы заменены на заглавные в соответствии с национальной кодировкой Windows

Function Concat(Sl [, S2, ..., SN]: String): String;

Возвращает строку, представляющую собой сцепление строк-параметров S1, S2, ... , SN

Function Copy(St: String; Index, Count: Integer): String;

Копирует из строки St count символов, начиная с символа с номером Index

Procedure Delete(St: String;

Index, Count:" Integers-

Удаляет count символов из строки St, начиная с символа с номером index

Procedure Insert(SubSt:

String; St, Index: Integer);

Вставляет подстроку SubSt в строку St, начиная с символа с номером Index

Function Length(St: String): Integer;

Возвращает текущую длину строки St

Function LowerCase(const S:String): String;

Возвращает исходную строку S, в которой все латинские заглавные буквы заменены на строчные

procedure OleStrToStrVar(Source: PWideChar; var Dest:String) ;

Копирует “широкую” (двухбайтную) строку в обычную строку Object Pascal

Function Pos(SubSt, St:String): Integer;

 

 

Отыскивает в строке St первое вхождение подстроки SubSt и возвращает номер позиции, с которой она начинается. Если подстрока не найдена, возвращается ноль

Procedure SetLength(St:String; NewLength: Integer); 

 

 

Устанавливает новую (меньшую) длину NewLength строки St. если NewLength больше текущей длины строки, обращение к SetLength игнорируется

function StringOfChar(Ch:Char; Count: Integer):String;

Создает строку, состоящую из Count раз повторенного символа ch 

function StringToOleStr(const Source: String):PWideChar;

Копирует обычную строку в двухбайтную 

function StringToWideChar(const Source: String; Dest:PWideChar; DestSize: Integer) : PWideChar;

Преобразует обычную строку в строку с символами UNICODE

Function Uppercase(const S:String): String;

Возвращает исходную строку S, в которой все строчные латинские буквы заменены на заглавные

Подпрограммы преобразования строк в другие типы

Function StrToCurr(St: String): Currency;

Преобразует символы строки St в целое число типа Currency. Строка не должна содержать ведущих или ведомых пробелов

Function StrToDate(St: String): TDateTime;

Преобразует символы строки St в дату. Строка должна содержать два или три числа, разделенных правильным для Windows разделителем даты (в русифицированной версии таким разделителем является “.”). Первое число - правильный день, второе - правильный месяц. Если указано третье число, оно должно задавать год в формате XX или ХХХХ. Если символы года отсутствуют, дата дополняется текущим годом. Например: DateToStr(StrToDate('28.06')) даст строку '28.06.99' (см. ниже пояснения)

Function StrToDateTime(St:

String): TDateTime;

 

 

 

 

Преобразует символы строки St в дату и время. Строка должна содержать правильную дату (см. StrToDate) и правильное время (см. StrToTime), разделенные пробелом, например: StrToDateTime('28.06 18:23')

Function StrToFloat(St:String): Extended;

 

 

Преобразует символы строки St в вещественное число. Строка не должна содержать ведущих или ведомых пробелов

Function StrToInt(St:String): Integer;

Преобразует символы строки St в целое число. Строка не должна содержать ведущих или ведомых пробелов

Function StrToIntDef(St:String; Default: Integer):Integer;

 

Преобразует символы строки St в целое число.

Если строка не содержит правильного представления целого числа, возвращается значение Default

Function StrToIntRange(St:String; Min, Max: Longint):Lomgint;

Преобразует символы строки St в целое число и возбуждает исключение ERangeError, если число выходит из заданного диапазона Min.. .мах

Function StrToTime(St:String): TDateTime;

 

 

 

 

 

 

 

 

 

 

Преобразует символы строки St во время.

Строка должна содержать два или три числа, разделенных правильным для Windows раздели телем времени (для русифицированной версии таким разделителем является “:”). Числа задают часы, минуты и, возможно, секунды. За послед ним числом через пробел могут следовать символы “am” или “рm”, указывающие на 12- часовой формат времени

Procedure Val(St: String; var

X; Code: Integer);

 

 

 

 

 

 

 

 

 

 

Преобразует строку символов St во внутреннее представление целой или вещественной переменной х, которое определяется типом этой переменной. Параметр Code содержит ноль, если преобразование прошло успешно, и тогда в х помещается результат преобразования, в противном случае он содержит номер позиции в строке St, где обнаружен ошибочный символ, и в этом случае содержимое х не меняется. В строке St могут быть ведущие и/или ведомые пробелы. Если St содержит символьное представление вещественного числа, разделителем целой и дробной частей должна быть точка независимо от того, каким символом этот разделитель указан в Windows

Подпрограммы обратного преобразования

Function DateTimeToStr(Value: TDateTime): String; Procedure DateTime-ToString(var St: String; Format: String;- Value: TData-Time);

Преобразует дату и время из параметра в строку символов Преобразует дату и время из параметра value в строку St в соответствии со спецификаторами параметра Format (см. пояснения ниже)

Function DateToStr(Value: TDateTime): String;

Преобразует дату из параметра value в строку символов

Function FloatToStr(Value: Extended): String;

Преобразует вещественное значение value в строку символов.

Function FloatToStrF(Value:

Extended; Format: TFloatPor-

mat; Precision, Digits: Inte

ger) : String;

Преобразует вещественное значение Value в строку символов с учетом формата Format и параметров precision и Digits (см. пояснения ниже).

Function Format(const Format: String; const Args: array of const): Strings;

 

 

Преобразует произвольное количество аргументов открытого массива Args в строку в соответствии с форматом Format (см. пояснения ниже)

Function FormatDateTime (Format: String; Value:.TDateTime): String;

Преобразует дату и время из параметра value в строку символов в соответствии со спецификаторами параметра Format (см. пояснения ниже)

Function FormatFloat(Format:String; Value: Extended): String;

Преобразует вещественное значение value в строку символов с учетом спецификаторов формата Format (см. пояснения ниже)

function IntToHex(Value: Integer; Digits: Integer):Strings;

Преобразует целое число Value в строку символьного представления шестнадцатеричного формата: Digits - минимальное количество символов в строке

Function IntToStr(Value: Integer) : String;

Преобразует целое значение Value в строку символов

Procedure Str(X [:Width[:Decimals]]; var St:String) ;

 

 

 

Преобразует число х любого вещественного илицелого типов в строку символов St; параметры width и Decimals, если они присутствуют, задают формат преобразования: width определяет общую ширину поля, выделенного под соответ ствующее символьное представление вещественного или целого числа х, a Decimals - количество символов в дробной части (этот параметр имеет смысл только в том случае, когда х -вещественное число)

Function TimeToStr(Value: TDateTime): String;

Преобразует время из параметра Value в строку символов

 

При преобразовании с помощью функций StrToxxx строка может содержать недопустимые для типа ххх символы. В этом случае возбуждается исключительная ситуация EConvertError. При обратных преобразованиях xxxToStr формат получаемой строки зависит от установленных в Windows системных параметров: разделителей даты, времени, целой и дробной частей вещественного числа.

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

procedure TfmExample.bbRunClick (Sender : TObject) ;

var S: String;

begin

S:=FloatToStrF(1000,ffNumber,4,0);

EdOutput.Yext:=IntToStr(Ord(S[2]));

end;

Если вы действительно хотите использовать пробел, его нужно явно указать в окошке. Разделитель: групп разрядов (Пуск.| Настройка | Панель управления | Язык и стандарты | Числа)

В Delphi 4...6 изменена функция StrToDate для того, чтобы упростить ввод двух цифр года с учетом смены столетия. С этой целью в модуле system введена глобальная переменная TwoDigitYearCenturywindow, которая определяет цифровой рубеж столетия. Если две цифры года больше или равны значению этой переменной, цифры года относятся к текущему столетию, если меньше - переносятся в следующее. Пусть, например, TwoDigitYearCenturywindow содержит значение 50. Тогда любые две цифры года в диапазоне 00..49 дополняются базой 2000 (2000, 2001,...,2049), в то время как цифры в диапазоне 50..99 дополняются базой 1900 (1950, 1951,...,1999). Такой прием позволяет в известной мере смягчить проблему двухцифровых годов на рубеже столетия, однако полным ее решением будет, разумеется переход на четырехцифровое представление года. По умолчанию TwoDigitYearCenturywindow имеет значение 0, и поэтому любые две цифры года дополняются базой 1900.

Используемая в процедуре DateTimeToString и в функции FormatDateTime строка Format может содержать такие символы-спецификаторы (в примерах показаны строки для времени 19 часов 45 минут и даты 8 июня 1999 года):

Таблица 7.8. Спецификаторы формата даты/времени

с

  

Отображает сначала дату в формате дд.мм.гг, затем пробел и время в формате чч.мм. ее: 08.06. 99 19:45

d

Отображает день без ведущего нуля: 8

dd

Отображает день с ведущим нулем: 0 8

dddd

Отображает день недели: воскресенье (для нерусифицированной версии Windows - Sunday)

ddddd

Отображает дату в формате дд. мм. гг: 08.06.99

dddddd

Отображает дату в формате д Месяц год: 8 Июнь 1999 (для нерусифицированной версии Windows - 8 June 1999)

m

Отображает число месяца без ведущего нуля: 6

mm

Отображает число месяца с ведущим нулем: 06

nunm

Отображает сокращенное название месяца: июн.

nuninm

Отображает полное название месяца: Июнь

у или уу

Отображает две последние цифры года: 9 9

ууу или уууу

Отображает все цифры года: 1999

h

Отображает час без ведущего нуля: 19

hh

Отображает час с ведущим нулем: 19

n

Отображает минуты без ведущего нуля: 4 5

nn

Отображает минуты с ведущим нулем: 4 5

s

Отображает секунды без ведущего нуля: 0

ss

Отображает секунды с ведущим нулем: 00

t

Отображает время в формате чч:лш: 19:45

tt

Отображает время в формате чч:мм:сс: 19:45:00

am/pm

Отображает время в 12-часовом формате (am - до полудня, pm - после полудня). Для спецификаторов hh: mm am/pm получим 07:45 pm

ampm

Отображает время в 12-часовом формате, но без указания до/после полудня. Для спецификаторов hh: mm ampm получим 07:45

a/p

Отображает время в 12-часовом формате (а - до полудня, р - после полудня). Для спецификаторов hh: mm a/p получим 07:45 р

/

Отображает используемый в Windows разделитель даты. Для спецификаторов d/m/у получим 8. 6. 99

:

Отображает используемый в Windows разделитель времени. Для спецификаторов h:n: s получим 19:45:0

 Замечу, что любые другие символы, указанные в строке Format, a также заключенные в апострофы или кавычки специальные символы-спецификаторы помещаются в выходную строку без преобразования, поэтому спецификаторы 'h час n мин' дадут строку 19 час 45 мин, а 'h час "n" мин' - 19час n мин.

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

Таблица 7.9. Системные переменные, управляющие стандартным отображением данных

CurrencyString: String;

 

Символ или символы денежной единицы; для русифицированной Windows ими являются символы “р. ”

CurrencyFormat: Byte; 

 

Определяет положение символов денежной единицы: 0 - $1; 1 - 1$; 2 - $ 1; 3 - 1 $; в русифицированной Windows используется формат 1 (1р.)

NegCurrFormat: Byte;

Определяет формат отрицательной суммы: 0 = ($1); 1 = -$1; 2 = S-1; 3 = $1-; 4 = (1$); 5 = -1$; 6 = 1-$; 7 =1$-; 8=-!$; 9=-$!; 10=1 $-; 11 =$1-; 12=$-!; 13= 1- $; 14 = (S 1); 15 = (1 $); в русифицированной Windows используется формат 5 (-lp.)

ThousandSeparator: Char; 

Разделитель тысяч; в русифицированной Windows используется символ #166

DecimalSeparator: Char;

Разделитель дробной и целой частей числа (', ')

CurrencyDecimals: Byte; 

 

 

Количество цифр после запятой в денежном формате. Обычно содержит 0, что блокирует вывод мелкой денежной единицы. Чтобы в сумме присут ствовали не только рубли, но и копейки, в переменную следует установить значение 2

DateSeparator: Char;

Разделитель даты; в русифицированной Windows используется ' . '

ShortDateFormat: String;   

 

 

 

Обычно используется формат ' dd. mm. уу ', что соответствует, например, дате '31.05.00'. По скольку на рубеже столетий цифры года в таком формате кажутся неверными, я советую в начале каждой программы вставлять оператор Short-DateFormat := 'dd.mm.yyyy'; это даст '31.05.2000'

LongDateFormat: String; 

Для русифицированной версии содержит символы 'dd MMMM yyyy г.',что дает'31 Май 2000 г. '

TimeSeparator: Char;

Разделитель времени (' : ')

TimeAMString: String; 

 

Символы 12-часового формата для времени до полудня (не используются в русифицированной версии Windows)

TimePMString: String; 

 

Символы 12-часового формата для времени после полудня (не используются в русифицированной версии Windows)

ShortTimeFormat: String;

Краткий формат времени (обычно ' h: mm ')

LongTimeFormat: String;

Полный формат времени (обычно ' hh: mm: ss ')

ShortMonthNames: array

[1..12] of String;

Краткие имена месяцев (янв, фев, мар, апр, май, июн, июл, авг, сен, окт, ноя, дек)

LongMonthNames: array

[1..12] of String; 

Полные имена месяцев (Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь)

ShortDayNames: array [1..7] of String;

Краткие имена дней недели (Вс, Пн, Вт, Ср, Чт, Пт, Сб)

LongDayNames: array [1..7] of String; 

 

Полные имена дней недели (воскресенье, понедельник, вторник, среда, четверг, пятница, суббота)

type TSysLocale = packed record DefaultLCID: LCID; PriLangID: LANGID;

SubLangID: LANGID;

FarEast: Boolean;

MiddleEast: Boolean; 

end;

var SysLocale: TSysLocale;

Определяет локализацию Windows: DefaultLCID- идентификатор локализации (1049); PriLangID- идентификатор первичного языка (25); SubLangID - идентификатор вторичного языка (если в качестве второго языка используется английский (США), это поле имеет значение 1); Far-East - локализация для Дальнего Востока (False): MiddleEast - локализация для Среднего Востока(False)

EraNames: array [1..7] of String;

Используется в функции DateTimeToStr в Windows для Ближнего Востока

EraYearOffsets: array [1..7] of Integer;

Используется в функции DateTimeToStr в Windows для Ближнего Востока

TListSeparator: Char;

Разделитель списка строк ('; ')

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

procedure WeekToDates(aDate: TDateTime; var Week: Byte;var Year: Word; var FirstDate, LastDate: TDateTime);

{Возвращает для указанной даты aDate год Year, номер недели от начала года Week, а также даты начала и конца недели} var

S: String;

begin

//Получаем в S символы года для даты aDate:

DateTimeToString(S,'yyyy',aDate) ;

//Формируем дату 1 января:

FirstDate := StrTo-Date('01'+DateSeparator+'01'+DateSeparator+S) ;

Year := StrToInt(S); //Возвращаем год

//Формируем последнюю дату 1-й недели:

LastDate := FirstDate;

DateTimeToString(S,'dddd',LastDate) ;

while SOLongDayNames [1] do

// LongDayNames [1 ]= 'воскресенье '

begin

LastDate := LastDate+1;

DateTimeToString(S,'dddd',LastDate);

end;

Week := 1;

//Циклически наращиваем FirstDate, LastDate и Week, пока

// LastDate не станет больше или равна aDate:

while LastDate<aDate do

begin

inc(Week);

FirstDate := FirstDate+7;

LastDate := LastDate+7

end

end; // WeekToDates

Для форматного преобразования вещественных чисел предназначены функции FloatToStrF и FormatFloat. Первая использует значение Format перечисляемого типа TFloatFormat и два дополнительных параметра - Precision и Digits. Правила использования параду метров функции FloatToStrF показаны в следующей таблице' (примеры преобразования даются для value = П = 3,141593654, Precision = 5 и Digits = 2):

Таблица 7.10. Правила использования параметров функции FloatToStrF

Значение Format

Описание

ffExponent

Научная форма представления с множителем ехх (“умножить на 10 в степени XX”). precision задает общее количество десятичных цифр мантиссы, Digits - количество цифр в десятичном порядке хх. Число округляется с учетом первой отбрасываемой цифры:3,1416Е+00

ff Fixed

Формат с фиксированным положением разделителя целой и дробной частей, precision задает общее количество десятичных цифр в представлении числа. Digits - количество цифр в дробной части. Число округляется с учетом первой отбрасываемой цифры:3,14

ff General

Универсальный формат, использующий наиболее удобную для чтения форму представления вещественного числа. Соответствует формату ff Fixed, если количество цифр в целой части меньше или равно precision, а само число - больше или равно 0,00001, в противном случае соответствует формату ff Exponent: 3,1416

ffNumber

Отличается от ffFixed использованием символа-разделителя тысяч при выводе больших чисел (для русифицированной версии Windows таким разделителем является пробел). Для value = П *1000 получим 3 141,60

ffCurrency

Денежный формат. Соответствует ffNumber, но в конце строки ставится символ денежной единицы (для русифицированной версии Windows - символы “р.”). Для value = я*1000 получим 3 141,60р.

Параметр Format в функции FormatFloat может содержать такие спецификаторы:

Таблица 7.11. Спецификаторы форматирования вещественных чисел

;

Разделитель спецификаторов формата для положительного, отрицательного и нулевого числа

0

Определяет поле для цифры. Если в данной позиции форматируемое число имеет значащую цифру, она выводится, если нет - выводится 0

#

Определяет поле для цифры. Если в данной позиции форматируемое число имеет значащую цифру, она выводится, если нет - ничего не выводится

.

Поле для разделителя целой и дробной частей числа

,

Поле для разделителя тысяч

E+,e+

E-,e-

Признак представления числа в научном формате. В этом случае число представляется мантиссой и десятичным порядком, между которыми стоит символ Е. Спецификаторы е+ и е+ предписывают выводить знак + перед неотрицательным десятичным порядком, при использовании Е- и е- знак + перед порядком не выводится

Как и в случае даты/времени, любые другие символы строки Format, а также заключенные в апострофы или кавычки специальные символы-спецификаторы помещаются в выходную строку без преобразования: для value = 71*1000 спецификаторы'#, рубля' дадут строку 3 142 рубля. С помощью символа “;” можно задавать различные формы представления положительного, отрицательного и нулевого числа. При этом набор спецификаторов без “;” относится ко всем числам; если используется один символ “;”, то спецификаторы слева от него применяются для форматирования положительных чисел, справа - отрицательных, а вывод нулей подавляется; при использовании двух символов “; ” первый набор - для положительных, второй - для отрицательных и третий - для нулевых чисел. Например, спецификаторы '#;нуль' для value = -1 выведут нуль, а для value = о ничего не выведут, в то время как спецификаторы '#;00;нуль' для value = -1 выведут 01, а для value = 0 - строку нуль. Спецификаторы '#;;нуль' для value = -1 выведут -1, т. к. в этом случае спецификатор для отрицательных чисел не задан и для их вывода будет использован спецификатор положительных чисел, в то время как спецификаторы '#; ;нуль' подавляют вывод отрицательных чисел.

Мощная функция преобразования Format (табл. 7.7) перешла в Object Pascal из языка Си. Она позволяет преобразовать сразу несколько элементов открытого массива аргументов в соответствии с указаниями форматирующей строки. Например, Format('Строка "%s" содержит %d символов',['Паскаль',7]) даст такой результат: Строка "Паскаль" содержит 7 символов.

Элементами массива аргументов могут быть константы и/или переменные целого и вещественного типа, строки и указатели.

Форматирующая строка - это произвольная строка, в которую в любом месте можно вставить форматирующий спецификатор. Количество форматирующих спецификаторов должно быть не больше количества элементов массива аргументов - в противном случае возникнет исключительная ситуация. Каждому элементу массива аргументов по порядку их перечисления в конструкторе массива функция ставит в соответствие форматирующий спецификатор по порядку его следования в форматирующей строке: первому аргументу - первый спецификатор, второму - второй и т. д. Если количество спецификаторов меньше количества аргументов, “лишние” аргументы игнорируются.

Форматирующий спецификатор всегда начинается символом процента и в общем случае имеет такую структуру (в квадратных скобках указываются необязательные элементы):

"%" [index ":"] ["-"] [width] ["." prec] type

Здесь: index ":" - индекс открытого массива, с помощью этого элемента можно явно указать аргумент, который будет обрабатывать спецификатор; "-" указывает на необходимость прижать отформатированный спецификатором текст к левой границе отведенного для него пространства; width - число, определяющее количество символов для обработанного спецификатором текста; если это число меньше требуемого, этот элемент спецификатора игнорируется, если больше - дополняется справа (если есть элемент "-") или слева (если он отсутствует) нужным количеством пробелов; "." prec - задает точность представления целых и вещественных типов; type - символ, определяющий тип форматирования (см. таблицу ниже).

Таблица 7.12. Форматирующие спецификаторы для функции Format

d

 

 

Целое десятичное число. Если задан параметр ргес, то символьное представле

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

Беззнаковое целое число. Используется подобно типу d, но аргумент должен быть положительным числом. Если аргумент - отрицательное целое, результат форматирования непредсказуем

е

 

 

Вещественное число в экспоненциальном представлении: символьное представление имеет вид -d, dddddddddddE+ddd. Если число положительное, ведущий минус опускается, а если его модуль меньше 1, знак плюс меняется на минус. Всегда содержит одну цифру целой части, по меньшей мере одну цифру дробной части и не меньше трех цифр десятичного порядка. Если задан параметр точности, он определяет общее количество цифр до символа Е, но не меньше двух: если параметр точности содержит 1 или 0, он заменяется на 2. Если символьное представление содержит больше символов, чем ргес, оно округляется по первой отбрасываемой цифре. Умалчиваемое значение параметра точности 15

 

Вещественное число в виде -ddd, ddd (фиксированное представление). Параметр точности (по умолчанию 2) указывает количество цифр в дробной части. Если он 0, выводится только целая часть числа

g  

 

 

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

Соответствует фиксированному представлению, но использует символ-разделитель тысяч

Денежное представление вещественного числа. Подобно типу n, но справа ставится знак денежной единицы

p

Указатель. Выводит содержимое указателя в виде 8 шестнадцатеричных цифр

s

Аргумент должен быть символом, строкой или строкой с терминальным нулем. Параметр точности, если указан, определяет максимальную длину строки: если строка больше, она усекается, если меньше - параметр точности игнорируется

x

Шестнадцатеричное представление целого числа. Параметр точности определяет минимальное количество шестнадцатеричных цифр (если число меньше, оно дополняется ведущими нулями)

Функция не чувствительна к высоте букв, указывающих тип преобразования. Параметры index, ргес и width задаются явно (числами в форматирующей строке) или неявно - с помощью символа “*”. В этом случае в качестве параметра берется значение очередного аргумента в списке аргументов (он должен быть целым числом). Например, два следующих обращения дадут одинаковый результат:

Format ('%*.*f, [8, 2, 123.456]);

Format ('%8.2f, [123.456]);

7.3.2. Нуль-терминальные строки

Нуль-терминальные строки широко используются при обращениях к так называемым API-функциям Windows (API - Application Program Interface - интерфейс прикладных программ). Поскольку компоненты Delphi берут на себя все проблемы связи с API-функциями Windows, программисту редко приходится прибегать к нуль-терминальным строкам. Тем не менее в этом разделе описываются особенности обработки таких строк.

Прежде всего напомню, что базовый тип string хранит в памяти терминальный нуль, поэтому Object Pascal допускает смешение обоих типов в одном строковом выражении, а также реализует взаимное приведение типов с помощью автофункций преобразования String и PChar. Например:

procedure TfmExample.FormActivate(Sender: TObject);

var

pcS: PChar;

ssS: String;

begin

pcS := '123456';

ssS := 'X = ';

IbOutput.Caption := ssS + pcS;

end;

В строке IbOutput будет выведено х = 123456. Другой пример. В состав API-функцией входят функция MessageBox, с помощью которой на экране создается диалоговое окно с заголовком, текстовым сообщением и набором кнопок. Если в конце предыдущего примера добавить оператор

MessageBox(0, ssS + pcS, 'Заголовок окна', mb_0k);

то компилятор укажет на ошибку, т. к. вторым параметром обращения к функции должно быть выражение типа PChar, в то время как выражение sss+pcs приводится компилятором к общему типу String. Правильным будет такое обращение:

MessageBox(0, PChar (ssS + pcS), 'Заголовок окна', mb_0k) ;

Текстовые константы совместимы с любым строковым типом, поэтому третий параметр обращения (он тоже должен быть типа PChar) компилятор обработает без ошибок.

В Delphi считается совместимым с pchar и string массив символов с нулевой нижней границей. В отличие от pchar и String такой массив распределяется статически (на этапе компиляции), поэтому наполнение массива символами и завершающим нулем осуществляется специальной процедурой Strcopy:

procedure TfmExample.bbRunClick(Sender:TObject);

var

acS: array [0..6] of Char;

begin

StrCopy(acS, '123456');

IbOutput.Caption := acS;

end;

Для работы с типом pchar используются такие же операции, как и с типом String: операция конкатенации “+” и операции сравнения >, >=, <, <=, =, <>.

Таблица 7.13. Подпрограммы для работы с нуль-терминальными строками

Function CharToOem

(Str, OemStr: PChar):

Bool;

Преобразует символы строки Str из кодировки ANSI в кодировку MS-DOS и помещает результат в OemStr.Всегда возвращает True

Function CharToOemBuff(Str, OemStr: PChar; MaxLen: Lorigint): Bool;

Преобразует не более MaxLen символов строки Str из кодировки ANSI в кодировку MS-DOS и помещает результат в OemStr. Всегда возвращает True

Function OemToChar (OEMStr, Str: PChar): Bool;

Преобразует символы из кодировки MS-DOS в кодировку ANSI и возвращает True

Function OemToCharBuff(OEMStr, Str: PChar;MaxLen: Longint): Bool;

Преобразует не более MaxLen символов строки OemStr из кодировки MS-DOS в кодировку ANSI и помещает результат в Str. Всегда возвращает True

Function StrCat(Dest,Source: PChar): PChar;

Копирует строку Source в конец строки Dest и возвращает указатель на строку Dest

Function StrComp (Strl,Str2: PChar): Integers;

Побайтно сравнивает строку Strl со строкой Str2 и возвращает следующий результат: =0 для Strl=Str2; >0 для Strl>Str2,- 0 для Strl<Str2

Function StrCopy(Dest,Source: PChar): PChar;

Копирует строку Source в строку Dest и возвращает указатель на Dest. StrCopy не проверяет реальный размер памяти, связанный с Dest (он должен быть не меньше StrLen(Source)+1)

Procedure StrDispose(Str: PChar) ; 

Удаляет строку Str из памяти. Строка должна быть предварительно помещена в память функцией StrNew. Если Str=NlL, процедура ничего не делает

Function StrECopy(Dest, Source: PChar): PChar; 

Объединяет строки. Эта функция работает в точности, как StrCat, но возвращает указатель на конец сцепленных строк, т. е. на терминальный ноль

Function StrEnd(Str:

PChar): PChar;

Функция возвращает указатель на терминальный нольстроки Str

Function StrIComp(Strl,Str2: PChar): PChar; 

 

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

Function StrLCat(Dest,Source: PChar; MaxLen:Word): PChar;

 

 

Копирует символы строки Source в конец строки Dest до тех пор, пока не будут скопированы все символы или пока длина сцепленной строки Dest не достигнет MaxLen. Возвращает указатель на сцепленную строку. В отличие от StrCopy эта функция блокирует возможноепереполнение области памяти, связанной с Dest. Обычно в качестве MaxLen используется выражение SizeOf(Dest)-!

Function StrLComp(Dest,

Source: PChar; MaxLen:

Word): PChar;

В отличие от StrComp сравнивает не более MaxLen символов строк. Возвращаемый результат такой же, как и у StrComp

Function StrLCopy(Dest,

Source: PChar; MaxLen:

Word): PChar; 

Копирует символы из строки Source в строку Dest до тех пор, пока не будет скопирована вся строка или пока не будет скопировано MaxLen символов. В отличие от StrCopy блокирует возможное переполнение области памяти, связанной с Dest. В качестве MaxLen обычно используется выражение SizeOf(Dest)-1

Function StrLen(Str:PChar): Cardinal;

Возвращает длину строки 

 

Function StrLIComp(Strl, Str2: PChar; MaxLen: Word): PChar; 

Сравнивает не более MaxLen символов строк, проверяя точное соответствие высоты букв. Возвращаемый результат см. StrComp. Функция правильно работает только с латиницей

Function StrLower(Str:

PChar): PChar;

Преобразует заглавные буквы строки Str к строчным и возвращает указатель на результат. Функция правильно работает только с латиницей

Function S t rMove(Dest,

Source: PChar; Count:Word): PChar;

Копирует точно Count символов строки Source в строку Dest и возвращает указатель на результат. Функция игнорирует действительные размеры строк и может выйти за их пределы

Function StrNew(Str:PChar): PChar;

Помещает строку в память

Function StrPas(Str:PChar): String;

Преобразует нуль-терминальную строку в строку String

Function StrPCopytStr: PChar; S: String):PChar;

Преобразует строку String в нуль-терминальную строку. Возвращает указатель на Str

Function StrPos(Strl,

Str2: PChar): PChar;

Ищет подстроку Str2 в строке Strl и возвращает указатель на первое вхождение Str2 или MIL, если подстрока не найдена

Function StrRScan(Str:

PChar; Ch: Char):PChar;

Ищет символ Ch в строке Str и возвращает указатель напоследний обнаруженный символ Ch или NIL, если символ не найден

Function StrScan(Str:PChar; Ch: Char):PChar;

Ищет символ Ch в строке Str и возвращает указатель на первый обнаруженный символ Ch или MIL, если символ не найден

Function StrUpper (Str: PChar) : PChar

Преобразует строчные буквы строки Str к заглавным и возвращает указатель на результат. Функция правильно работает только с латиницей

Функции преобразования из ANSI-кодировки в кодировку MS-DOS (charToxxx) и обратно (OеmTоххх) правильно работают с кириллицей, если в MS-DOS используется национальная страница 866 (так называемая альтернативная кодировка). А вот четыре функции, использующие преобразование высоты букв (strLower, StrUpper, Stricomp и StrLIComp), работают корректно только для букв латинского алфавита (латиницы). Для русских букв вместо обращения к этим функциям следует использовать стандартные функции AnsiLowerCase И AnsiUpperCase, которые используют как параметры String, так и PChar, но возвращают результат типа string:

var

acS: array [Byte] of Char;

begin

StrCopy(acS, 'заглавные буквы');

Caption := AnsiUpperCase(acS) end;

Аналогично для функции Stricomp:

var

apSl,apS2: array [0..1000] of Char;

begin

StrCopy(apSl,'эталон');

StrCopy(apS2,'ЭТАЛОН') ;

Caption := IntToStr(StrIComp(PChar(AnsiUpperCase(apSl)),

PChar(AnsiUpperCase(apS2))))

end;