Программирование на Lazarus

Символы и строки

Разбить на страницы
Показывать лекцию целиком

Цель лекции

Знакомство с символьными и строковыми типами данных, использование компонентов для работы со строками.

Понятия "символ" и "строка"

Для рядового пользователя эти понятия весьма абстрактны. Когда он вводит с клавиатуры "А", то считает это символом, буквой. Когда вводит "4", то это - цифра. А про всякие там пробелы, знаки препинания или арифметические знаки он и вовсе не думает. Но программист должен понимать, как все эти знаки воспринимаются компьютером. Поэтому наберитесь терпения, мы изучим эти понятия достаточно подробно.

На самом деле, всё, что мы вводим с клавиатуры - это символы. Буква "z", цифра "3", пробел, знак умножить, знак процента и т.д. - всё это символы. Компьютер же может оперировать только цифрами, причем двоичными - такими, которые содержат лишь 0 или 1. Все эти буквы, десятичные цифры и прочие знаки для него не значат ровным счетом, ничего. И для того, чтобы мы могли как-то обрабатывать текст, цифры и прочую информацию, нужно было придумать специальную систему для перевода информации в понятную компьютеру, и обратно. Так появились кодовые страницы.

Кодовая страница (англ. code page) - специальная таблица, сопоставляющая каждому значению байта некоторый символ.

Не очень понятно? Давайте разбираться. Мы знаем, что информация измеряется байтами, и что в одном байте 8 бит. Бит - это минимальная единица информации, с которой может работать компьютер. В бите может храниться либо 0, либо 1.

На заре развития компьютеров была разработана кодовая страница ASCII (англ. American Standard Code for Information Interchange - Американский кодовый стандарт для обмена информацией). Первая версия этого стандарта появилась в 1963 г. Эта страница содержала 7-ми битные символы, в каждом байте один бит был не задействован. Минимальное двоичное число, которое могло храниться в 7-ми битах - это ноль. Максимальное - 1111111.

Нажмите кнопку "Пуск", выберите команду "Выполнить" и в окне "Запуск программы" укажите

calc
    

и нажмите <Enter>. Загрузится стандартный калькулятор Windows. В главном меню программы, в разделе "Вид" выберите "Инженерный". В левой части калькулятора, ниже поля ввода чисел, вы увидите переключатели различных систем исчисления:

(рис 5.1) Переключатели калькулятора

Здесь мы имеем возможность переключаться на четыре системы исчисления:

  • Hex - 16-ричная. Используется в основном, в языке Ассемблере или при отладке программ.
  • Dec - 10-тичная. Наша обычная система, используется по умолчанию.
  • Oct - 8-ричная. Почти не используется.
  • Bin - 2-ичная. Хоть она и является для компьютера единственно понятной, но вследствие громоздкости записей, в программировании её обычно не применяют.
  • Давайте посмотрим, сколько символов могло содержаться в кодовой странице ASCII. Переключитесь на двоичную систему (Bin), введите 7 единиц, затем переключитесь обратно на десятичную систему (Dec). У нас получилось 127. Именно столько символов содержалось в первой ASCII таблице. Помимо латинских букв, таблица содержала и другие символы - цифры, арифметические знаки, знаки препинания, символы пробела, скобки и т.п. Каждому символу соответствовал собственный номер в таблице. Если мы вводили английскую букву "A", то в компьютер попадал номер этого символа в таблице - 65. Или, в двоичном виде, 100 0001. Таким образом, символы можно было сравнивать между собой. Английское "B" находилось под номером 66 и, следовательно, было больше, чем "A". Строчные буквы имели другие номера, например, "a" шла в таблице под номером 97 и считалась большей, чем "A". Мы вводим символы, которые автоматически преобразовываются в цифры, с которыми уже оперирует компьютер.

    Тут нужно сделать одно важное пояснение. Если мы вводили число "65", то для ПК это не было числом 65, или латинской буквой "A", это было двумя символами "6" и "5". Символу "6" соответствует номер 54 кодовой таблицы, а символу "5" - номер 53. Таким образом, числа, которые мы вводим в ПК, на самом деле не числа, а текстовые символы! Преобразования таких символов в числа и обратно обычно производятся программой автоматически. Такие преобразования, например, постоянно выполняет стандартный калькулятор Windows. А когда мы будем изучать числа, нам самим придется выполнять такие же преобразования.

    Всё бы хорошо, но помимо английского языка, в мире существует множество других языков! Мы, например, пишем кириллицей - русским начертанием символов. 127 символов было явно недостаточно, чтобы можно было вводить текст и на других языках. Поэтому таблица ASCII развивалась, из года в год появлялись новые стандарты. Каждый символ стал уже 8-ми битным. Посмотрите на калькуляторе - восемь бит могут содержать максимальное число 1111 1111, при переводе в десятичную систему мы получим 255 символов. Первая половина таблицы оставалась неизменной, зато вторую половину таблицы можно было задействовать для символов других языков и псевдографики, с помощью которой программисты времен MS-DOS рисовали окошки, панельки, таблицы и меню. Однако и этого было слишком мало, чтобы закодировать символы всех языков на Земле. Для каждого языка приходилось разрабатывать свой стандарт, несовместимый с другими. Причем, для одного языка могло быть разработано несколько стандартов! Для русского языка, например, имеются стандарты CP866 (Code Page 866), KOI8-R, KOI8-U, ISO-8859-5, и это только самые распространенные! В хаосе стандартов надо было как-то разбираться, совершенствовать их.

    На смену ASCII пришла кодировка ANSI (англ. American National Standards Institute - Американский Национальный Институт Стандартов). Так, в MS Windows кодовая страница ANSI, содержащая кириллицу - это Windows-1251 (или CP1251), которая появилась в 1990-1991 гг.

    Однако и этого было недостаточно, ведь для каждого языка по-прежнему требовалась собственная кодировка, а языков на Земле много. Назрела необходимость переходить к "широким" стандартам, в которых символ занимает более одного байта. Так, в 1991 г. был предложен стандарт Юникод (англ. Unicode) - универсальная система кодирования символов, представляющая знаки практически всех языков. В этом стандарте в одном документе можно использовать символы кириллицы, китайские или японские иероглифы, знаки математических формул, музыкальные знаки и т.п.

    Первая версия Юникода имела фиксированный размер символов 2 байта (16 бит). В одной кодировке уже можно было использовать 65 535 символов! Однако оказалось, что и этого недостаточно. Юникод получил дальнейшее развитие, и из года в год стали появляться новые версии и стандарты, основанные на Юникоде. Имеются такие стандарты, как UTF-8 (англ. Unicode Transformation Format, 8 bit - 8-ми битный формат преобразования Юникода), UTF-16, UTF-32.

    В Lazarus, в основном, используется формат UTF-8, так что разберем его. UTF-8 появился 2 сентября 1992 года. Основное его отличие от первоначального Unicode в том, что в UTF-8 символы имеют не фиксированный размер! Если используются символы с номером меньшим, чем 128, то они занимают 1 байт, как обычный ASCII-текст. Символы с номером от 128 и больше могут занимать от 2 до 6 байт (реально максимальный размер символа - 4 байта, т.к. в Юникоде нет символов с большим номером). Символы кириллицы занимают, например, по 2 байта. Так что цепочка символов в 5 байт в UTF-8 не всегда означает строку из пяти символов.

    Такой подход делает UTF-8 самой экономичной кодировкой для совместимости со старыми стандартами, однако есть и минусы. К сожалению, для русскоязычных (и вообще для всех не англоязычных) пользователей Windows в Lazarus придется столкнуться с некоторыми проблемами применения различных кодировок: в Lazarus используется кодировка UTF-8, ОС Windows использует UTF-16, а в консольных приложениях Windows используется системная кодировка CP866 (то есть, стандарт ANSI). Её же используют некоторые функции компилятора FPC. Так что в некоторых случаях нам придется пользоваться функциями преобразования кодировок, например, UTF8ToConsole(), CP866ToUTF8() и т.п. Мы познакомимся с ними позже, в свое время.

    Итак, подведем некоторые итоги.

  • Символ - это графическое изображение буквы, цифры, арифметического знака, знака препинания или какого-либо другого знака, отвечающее какому-либо стандарту кодировки символов.
  • Каждому символу соответствует его номер в кодовой таблице символов.
  • Кодировок (code page) существует множество.
  • Строка - это цепочка символов.
  • Цифры, которые мы набираем на клавиатуре - это символы. Чтобы обрабатывать их, как цифры, программа выполняет автоматическое преобразование из символов в цифры, и обратно, когда выводит нам результаты вычислений.
  • UTF-8 - это одно из представлений Юникода, используемое в Lazarus.
  • В одной строке могут встречаться символы, которые занимают 1, 2 или даже больше байт.
  • Символьные типы данных

    В Lazarus имеется символьный тип Char. Переменная такого типа занимает ровно один байт памяти и может содержать любой ASCII - символ. Русскому языку с этим типом не повезло - поскольку символы кириллицы занимают по 2 байта, использовать этот тип с русскими буквами нельзя. Давайте откроем Lazarus с новым проектом. Если Lazarus у вас уже загружен, закройте старый проект командой Файл -> Закрыть, и создайте новый проект командой Проект -> Создать проект -> Приложение. Сразу же сохраните проект в папку 05-01 там, где вы храните все проекты лекций, проекту дайте имя MyStrings, и не забудьте назвать модуль главной формы Main, а саму форму fMain. Пусть это войдет у вас в привычку. Как всё это делается, вы должны знать по предыдущим лекциям. Не вздумайте давать своим проектам имена, используя ключевые (зарезервированные) слова. Например, нельзя давать проекту или модулю имя Strings, поскольку это слово зарезервировано, но MyStrings можно.

    Прямо посреди формы установите кнопку TButton, дважды нажмите на нее, чтобы сгенерировать обработчик OnClick. В обработчике создадим раздел переменных var, укажем там одну переменную типа Char, и запрограммируем следующий код:

    procedure TfMain.Button1Click(Sender: TObject);
    var
      ch1: Char; //переменная символьного типа
    begin
      ch1:= 'Z';
      ShowMessage(ch1);
    end;
        

    Как видим, здесь мы переменной ch1 присвоили значение - символ "Z". Запомните правило:

    Символы и строки в Lazarus должны быть заключены в одинарные кавычки. Если требуется ввести в текст одинарную кавычку (например, в слове can't), то следует указать две таких одинарных кавычки, которые также заключены в одинарные кавычки.

    Например:

    Mystring:= 'I can' + '''' + 't';
        

    Этот пример выполнять не нужно, он просто демонстрирует использование кавычек в строковых выражениях, и возможность в выражении соединять несколько строк в одну с помощью знака "+". Однако вернемся к нашему проекту. После того, как мы присвоили символьной переменной большую английскую букву "Z", мы вывели содержимое переменной с помощью строки

    ShowMessage(ch1);
        

    Сохраните проект, скомпилируйте его и выполните. Когда программа с кнопкой появится на экране, нажмите нашу единственную кнопку - выйдет сообщение с буквой "Z":

    (рис 5.2) Вывод символа

    Таким образом, мы можем работать с отдельными символами. Однако если вы исправите код, и вместо буквы "Z" в строке

    ch1:= 'Z';
        

    укажете русский символ, то при попытке скомпилировать и запустить проект выйдет ошибка "Error: Incompatible types: got "Constant String" expected "Char"" - несовместимость типов String (строка) и Char (символ). Поскольку русские буквы занимают по два байта, Lazarus их считает строкой символов. Однако это не значит, что мы совсем не имеем возможности работать с отдельными символами кириллицы.

    Ранее упоминалось, что в Lazarus используется формат UTF8. Для поддержки этого формата были разработаны расширенные типы данных, в том числе и символьные. Так, имеется тип TUTF8Char, который позволяет работать с любыми отдельными символами, в том числе и русскими. Имеет смысл всегда использовать его вместо стандартного Char. Но для этого нам нужно будет подключить модуль LCLType, где этот тип описан.

    Перейдите в редактор кода и пролистайте код модуля вверх. Там вы увидите раздел uses (англ. use - использовать), где перечислены подключенные модули. Нам нужно поставить после последнего модуля запятую и добавить наш подключаемый модуль:

    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
      LCLType;
        

    Если строка получается длинной, то после запятой можно переносить текст на другую строку.

    Теперь вернемся к обработчику нажатия на кнопку и переделаем его:

    procedure TfMain.Button1Click(Sender: TObject);
    var
      ch1: Char;
      ch2: TUTF8Char;
    begin
      ch1:= 'Z';
      ch2:= 'Я';
      ShowMessage(ch1);
      ShowMessage(ch2);
    end;
        

    Теперь всё сработает как надо, и русский символ "Я" выйдет так же, как английский "Z".

    Однако, это еще не всё. Символы можно вводить, указывая их номер в таблице символов. Для этого перед номером нужно указать символ "#", например:

    ch1:= #90;
        

    Под номером 90 находится буква Z в таблице символов, так что результат не изменится. Также в строковых выражениях можно указывать и специальные символы. Например, символ под номером 13 - это символ перехода на другую строку. Давайте снова немного изменим код:

    procedure TfMain.Button1Click(Sender: TObject);
    var
      ch1: Char;
      ch2: TUTF8Char;
    begin
      ch1:= #90;  //буква Z
      ch2:= 'Я';
      ShowMessage(ch1 + #13 + ch2); //вывод двухстрочного сообщения
    end;
        

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

    Строковые типы данных

    В Lazarus основным строковым типом является String (англ. string - строка). На форму нашего проекта разместите еще одну кнопку. Её обработчик будет выглядеть так:

    procedure TfMain.Button2Click(Sender: TObject);
    var
      s: String;
    begin
      s:= 'Это строка из пяти слов!';
      ShowMessage(s);
    end;
        

    Как видите, поскольку строка в Lazarus имеет формат UTF8, то никаких особых ухищрений для работы со строками тут не нужно, в переменную типа String можно записать любой, в том числе и русский текст. Размер строки String неограничен, однако имеется возможность жестко задать размер. Такой способ используется, когда вы точно знаете, что больше данного размера строка не будет. В этом случае размер указывается после ключевого слова String в квадратных скобках, например:

    var
      MyStr: String[50];
        

    В переменную MyStr можно записать до 50 символов. Максимальный размер строки, который можно жестко задать таким способом - 255 символов. Однако имеются в виду символы ASCII, то есть английские, однобайтовые. Пример:

    var
      s: string[7];
    begin
      s:= 'Привет!';
      ShowMessage(s);
    end;
        

    Данный пример ошибки не вызовет, однако сообщение выйдет не полностью, а обрезанным: "При". То есть, три первых буквы заняли 6 байт, четвертая уже не уместилась. В данном случае будет правильным указать размер не 7, а 14 - по удвоенному количеству букв. Впрочем, на практике обычно применяют тип String без ограничений, в этом случае строка обрабатывается правильно.

    Имейте в виду, что тип String является динамичным, то есть, заранее память для него не выделяется. Строго говоря, выделяется память на указатель строки, а не на саму строку. Физически строке выделяется необходимая память только в момент присвоения ей какого-то значения. Однако нередко возникает необходимость очистить такую строку. Для этого достаточно присвоить ей пустые кавычки, без пробелов и без каких-либо других символов:

    s:= '';
        

    В этом случае, строке присваивается значение Nil, то есть ноль, ничего, и строка становится пустой.

    Строковой переменной можно присваивать значения символьных переменных или констант, например:

    var
      c: Char;
      s: String;
    begin
      c:= 'Z';
      s:= c;
        

    Помимо String в Lazarus есть и другие строковые типы.

    ShortString Короткая строка, которая может содержать максимум, 255 ASCII-символов. То есть, ShortString - это String[255].
    AnsiString Строка неограниченной длины из ANSI-символов. Фактически всё, что мы говорили про String, относится именно к AnsiString. Отдельного типа String как такового, не существует, это просто сокращенная запись AnsiString. Однако это зависит от настроек. Есть в Паскале такие переключатели, которые еще называют директивы компилятора. Такие директивы подобно комментариям, заключают в фигурные скобки, а первым символом должен быть символ доллара. Тип, который будет использован в качестве String, зависит от директивы {$H}. Если она выключена {$H-}, то при указании типа String будет подразумеваться тип ShortString. Если она включена {$H+} - то AnsiString. По умолчанию переключатель включен, вы сможете это увидеть в третьей строке модуля, пролистав его код вверх:
    unit Main;
    
    {$mode objfpc}{$H+}
            

    На практике короткую строку используют крайне редко, ведь если нужна короткая строка, то ее размер можно указать явно. Поэтому данный переключатель исправлять вручную обычно не приходится. Давайте считать, что String и AnsiString - это одно и то же.

    PChar Строка в стиле C/C++ с нулевым символом в конце. Такой тип строк используется в функциях Windows API, поэтому имеет поддержку и в Lazarus. Что это за строка такая? Дело в том, что обычные строки динамические, то есть фактически переменная типа String - это указатель на строку. Эта переменная хранит физический адрес строки в памяти, и количество занимаемых ею байт. Строка типа PChar устроена несколько иначе. Это тоже указатель на строку, но он не хранит её размер. А как тогда компилятору знать, сколько байт нужно считывать при обращении к такой переменной? Дело в том, что в строках типа PChar завершающим всегда будет нулевой символ, то есть, символ #0. Если такой символ поместить внутри строки, то компилятор не будет читать всю строку. Встретив символ #0, он решит, что строка закончена. Мы будем использовать PChar, когда дойдем до функций WinAPI.

    Как правило, строкам одного типа можно присваивать значения строк другого типа, компилятор автоматически преобразует текст. Исключение составляют строки PChar, тут нам придется делать преобразование вручную, с помощью функции PChar(). Исправим обработчик второй кнопки:

    procedure TfMain.Button2Click(Sender: TObject);
    var
      s1: String; //он же AnsiString
      s2: ShortString;
      s3: PChar;
    begin
      s1:= 'Это строка из пяти слов!';
    
      //Теперь присвоим тот же текст в ShortString:
      s2:= s1;
    
      //Тот же текст в PChar. Для преобразования строки в этот тип
      //используем функцию PChar():
      s3:= PChar(s1);
    
      //Соберем сообщение из трех разнотиповых строк. Каждый тип
      //выведем в отдельной строчке:
      ShowMessage(s1 + #13 + s2 + #13 + s3);
    end;
        

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

    Имеются еще типы UnicodeString и WideString, оба типа содержат двухбайтовые символы. Но работать с такими типами неудобно - возникают проблемы с кириллицей, для нас гораздо удобней простой String. Поэтому рассматривать данные типы мы не будем.

    Резюмируем некоторые положения:

  • Три основных строковых типа: AnsiString, ShortString и PChar.
  • Обычно указывают тип String. Если переключатель {$H} включен (по умолчанию), то используется тип AnsiString. Иначе - ShortString.
  • Строке можно присвоить либо текст, заключенный в одинарные кавычки, либо содержимое другой строковой переменной, например:
  • s1:= 'Текст';
    s2:= s1;
        
  • Строке типа PChar можно присвоить либо текст, либо содержимое другой строковой переменной. Но если тип этой переменной отличается, то нужно сделать преобразование функцией PChar():
  • var
      s: String;
      pc: PChar;
    begin
      s:= 'Текст';
      pc:= 'Текст'; //присвоили текст
      pc:= PChar(s); //присвоили преобразованное значение переменной s
        

    Компоненты для ввода строк

    Теперь мы знаем, что такое строки, самое время разобрать способы предоставления пользователю возможностей эти самые строки вводить в нашу программу. Помните второй проект второй лекции? Там мы предлагали пользователю ввести свое имя, которое затем использовали в приветствии. Для этого мы использовали компонент TEdit. Разберем его возможности, и познакомимся с другими аналогичными компонентами.

    Для этого закройте старый проект и создайте новый. Как всегда, главную форму назовите fMain, и сохраните проект. При этом проекту дайте имя EditControls (контролами программисты между собой называют компоненты, с помощью которых программа взаимодействует с пользователем), а модуль этой формы назовите Main. Проект сохраните в папку 05-02 там, где у нас хранятся все остальные проекты.

    Компонент TEdit

    На форму установите компонент TEdit (если не помните, где он находится, смотрите рис. 2.5 в лекции №2). По умолчанию, он имеет ширину 80 пикселей (свойство Width), увеличьте его до 200. Теперь давайте разбираться с основными свойствами этого компонента, которые могут нам понадобиться, для этого он должен быть выделен.

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

    Align Выравнивание компонента. С этим свойством мы уже знакомы, оно позволяет компоненту занять весь верх, низ, левую или правую сторону, или же всю форму или панель, на которой компонент находится. В компоненте TEdit это свойство тоже есть, но применяется очень редко - трудно придумать ситуацию, в которой этот компонент потребуется таким образом выровнять. Обычно это свойство не трогают. Значения этого свойства должны быть вам знакомы по лекции №3.
    Alignment Выравнивание текста. Вот это свойство используется чаще. Оно позволяет выровнять текст в компоненте по центру, по левому или правому краю. Как выравнивать текст, обычно каждый решает для себя сам, но есть некоторые рекомендации: простой текст выравнивают обычно по левому краю, цифры - по правому, а такие данные, как дата-время можно выровнять по центру. Итак, значения этого свойства:
  • taCenter - по центру.
  • taLeftJustify - по левому краю. Это значение используется по умолчанию.
  • taRightJustify - по правому краю.
  • Anchors Привязка компонента к краям формы или панели, на которой компонент находится. С этим свойством вы также знакомы по третьей лекции.
    AutoSelect Автоматическое выделение текста. Если свойство равно True (по умолчанию), то когда компонент становится активным, выделенным, или как говорят, получает фокус ввода, текст в компоненте, если он есть, автоматически выделяется. Иначе текст будет невыделен.
    CharCase Регистр символов текста в компоненте. Может иметь следующие значения:
  • ecLowerCase - Все символы строчные (обычные), даже если набирать текст с нажатой клавишей <Shift> или с включенной <Caps Lock>.
  • ecNormal - Обычный текст, в котором могут быть и строчные, и прописные символы. Используется по умолчанию.
  • ecUpperCase - Все символы прописные (заглавные).
  • Color Позволяет выбрать цвет фона в компоненте.
    Font Позволяет выбрать шрифт, используемый в компоненте. Вообще каждый решает сам, как будет выглядеть дизайн его программы, однако желательно для всех компонентов использовать один и тот же шрифт. Если вас не устраивает шрифт по умолчанию, поменяйте его для всей формы, и он автоматически будет использоваться для всех компонентов, которые вы на этой форме установите! Если же в вашем проекте будет много форм, то выработайте для них какие-то одни стандарты (шрифт, цвет фона, обрамление и т.п.), и придерживайтесь их во всех формах.
    Hint Текст подсказки, который будет всплывать, когда пользователь подведет к компоненту указатель мыши.
    MaxLength Максимальный размер текста в символах. По умолчанию равен нулю, что снимает ограничение в размерах. Если текст не умещается в поле ввода, он будет прокручиваться. Ограничение на количество символов иногда бывает необходимо, например, если текст будет записан в базу данных или запись, которые имеют фиксированный размер строки. Во всех остальных случаях свойство можно не изменять.
    PasswordChar Символ, скрывающий пароль при вводе. Очень интересное свойство. Должно быть, всем приходилось когда-то вводить пароль. И обычно вместо нужных букв и цифр в этом поле отображались звездочки или кружочки. На самом деле, текст остается неизменным, но он прячется от тех, кто может оказаться у вас за спиной и подсмотреть ваш пароль. Реализуется эта возможность как раз данным свойством. Здесь нужно указать номер символа в таблице символов. По умолчанию, это #0 - нулевой символ, означающий, что текст выводится, как есть. Но можно поставить и другой символ, причем указать именно символ, а не его номер. Давайте в этом свойстве укажем символ "*". Как только вы нажмете <Enter>, сразу же изменится и свойство EchoMode - оба эти свойства взаимосвязаны. Мы разберем его чуть ниже, а пока сохраните проект и запустите на выполнение. Теперь любой текст, включая пробелы и другие знаки, будет выводиться на экран в виде звездочек. Однако это не все.

    Мы имеем возможность маскировать пароль и другими символами. Выделите компонент TEdit и измените его свойство Font, выбрав там шрифт Wingdings (если у вас ОС Windows). Это тот редкий случай, когда имеет смысл выбрать другой шрифт для отдельного компонента. Теперь нам нужно выбрать символ. Откройте редактор MS Word. Там выполните команду Вставка -> Символ:

    (рис 5.3) Определение кода символа

    В поле "Шрифт" выберите Wingdings, затем выберите подходящий символ, например, книгу. Потом посмотрите код выбранного знака, в данном случае это 38. Нажмите "Отмена" и закройте MS Word - он нам больше не нужен. Теперь вернитесь к проекту и в свойстве PasswordChar укажите #38 - код выбранного нами знака. Когда нажмете <Enter>, то значение #38 изменится на - не обращайте внимание. Сохраните проект и запустите его на выполнение - текст будет скрываться за пиктограммой книги. Используя различные шрифты, вы можете подобрать для себя и другие подходящие символы.

    EchoMode Тип сообщения. Связан с PasswordChar, и обычно устанавливается автоматически, но можно установить его и вручную. Имеет следующие значения:
  • emNone - вместо символов выводятся пробелы. Сам текст не меняется.
  • emNormal - обычный тип, используется по умолчанию. Устанавливается, если в PasswordChar установлено значение #0.
  • emPassword - тип пароля. Устанавливается, если в PasswordChar вы укажете другое значение, не #0. Сам текст не меняется.
  • ReadOnly Только для чтения. Разрешает или запрещает пользователю ввод текста. Если False, то пользователь может и читать, и вводить текст, иначе он может только читать его. Однако в любом случае вы можете менять там текст программно. Позже мы разберем такую возможность.
    Text Основное свойство этого компонента. Содержит текст, введенный пользователем, или установленный в компоненте программно. Причем даже если вы его скроете, как пароль, сам текст меняться не будет. К этому свойству можно относиться, как к строковой переменной, которую может изменять пользователь. По умолчанию, в это свойство сразу же прописывается имя компонента, в нашем случае, edit1. На практике такой текст вряд ли понадобится, поэтому программист обычно очищает это свойство. Очистите его и вы. Как только для подтверждения нажмете <Enter>, текст в компоненте на форме исчезнет.

    Остальные полезные свойства должны быть вам знакомы по предыдущим лекциям. Итак, установите для компонента Edit1 шрифт Times New Roman, размер шрифта пусть будет 11. В свойстве PasswordChar пусть будет значение по умолчанию - #0. Свойство Text очищено, а свойство ReadOnly установлено в True. Теперь ниже TEdit установите кнопку, сгенерируйте для нее обработчик нажатия, и введите там следующий код:

    procedure TfMain.Button1Click(Sender: TObject);
    begin
      Edit1.Text:= 'Привет!';
    end;
            

    Здесь мы программно меняем текст в компоненте. Для этого мы обращаемся к нему по имени - Edit1, после чего ставим точку. Обратите внимание - если поставить точку и чуть подождать, всплывет окошко со всеми свойствами, методами и событиями, которые мы можем использовать. Нам нужно свойство Text. Как только мы введем первую "T", список отфильтруется, оставив там только команды на букву "T". Как только мы введем следующую букву "e", то в списке останется только одно подходящее свойство - "Text". То, что нужно. Можно просто нажать <Enter>, не вводя остальных символов, и свойство само вставится в код. Причем вместе с последующим оператором присваивания. Мелочь, а приятно. Останется только указать строку, которую мы хотим присвоить.

    Таким образом, можно менять программно многие (но не все) свойства компонентов, их размеры и положение, текст и цвет, и многое другое. Сохраните проект и запустите его на выполнение. Если вы все сделали правильно, то пользователь не сможет вписывать текст в Edit1, а при нажатии кнопки Button1, текст там поменяется программно. Теперь давайте чуть изменим команду присваивания:

    Edit1.Text:= Edit1.Text + 'Привет! ';
            

    С выражениями мы уже работали, так что тут трудностей быть не должно. Мы просто берем текст, который уже был в свойстве Text (при первом нажатии там будет пустая строка), и прибавляем к нему строку 'Привет! ' - не забудьте после восклицательного знака поставить пробел, чтобы текст не слипался друг с другом. Сохраните проект и запустите его. Нажимая кнопку, мы сможем многократно добавлять слово 'Привет! ' в компонент.

    Компонент TLabelEdit

    На вкладке Additional Палитры компонентов есть странный компонент TLabelEdit:

    (рис 5.4) Компонент TLabelEdit

    Установите его на свободное место на форму, и посмотрите на его свойства в Инспекторе объектов. В общем-то, это гибрид метки TLabel и текстового поля TEdit. Свойства почти все знакомы, но есть и некоторые различия.

    EditLabel - раскрывающее свойство, внутри которого находится свой набор подсвойств для метки. Слева от этого свойства мы видим кнопку "+", щелкнув по которой раскроем подсвойства. Здесь нам понадобится, прежде всего, свойство Caption, в котором мы можем записать текст метки. Этот текст будет пояснять назначение текстового поля. Напишем в этом свойстве Фамилия, текст метки изменится, а пользователь сразу поймет, что сюда он должен будет вписать свою фамилию:

    (рис 5.5) Компонент TLabelEdit в Инспекторе объектов и в Редакторе форм

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

    LabelPosition - местонахождение метки. Может быть:

  • lpAbove - сверху текстового поля. Это значение по умолчанию.
  • lpBelow - снизу текстового поля.
  • lpLeft - слева
  • lpRight - справа
  • LabelSpacing - расстояние в пикселях между меткой и текстом. По умолчанию равно 3 пикселя. Изменяя это значение, можно приближать метку к полю или отодвигать ее.

    В остальном, этот компонент почти полностью идентичен обычному TEdit.

    TLabelEdit будет полезен при создании форм, где пользователь должен вписывать различные данные, для этого раньше применялись отдельно TLabel и TEdit. Данный гибрид, безусловно, удобней.

    Компонент TMaskEdit

    На той же вкладке Additional находится еще один полезный компонент для ввода строк - TMaskEdit:

    (рис 5.6) Компонент TMaskEdit

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

    Установите TMaskEdit на форму и посмотрите на его свойства в Инспекторе объектов. В принципе, все свойства нам знакомы. Интерес вызывает лишь одно свойство EditMask. Это сложное раскрывающееся свойство, то есть, щелкнув по кнопке с тремя точками правее свойства, можно его раскрыть:

    (рис 5.7) Раскрывающееся свойство EditMask

    Когда оно раскрыто, мы видим следующую картину:

    (рис 5.8) Редактор масок

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

    Символы маски компонента TMaskEdit
    0 В данной позиции должна быть цифра. Если пользователь введет не все цифры маски, будет создана исключительная ситуация, и он не сможет продолжать работу, не заполнив все положенные цифры. Если такая ситуация возникла у вас во время тестового выполнения программы, можете закрыть программу командой "Запуск->Сбросить отладчик".
    9 В данной позиции может быть либо цифра, или ничего.
    # В данной позиции может быть знак "+", "-", цифра, или ничего.
    L В данной позиции должна быть буква.
    l В данной позиции должна быть буква или ничего.
    A В данной позиции должна быть буква или цифра.
    a В данной позиции должна быть буква или цифра, или ничего.
    C В данной позиции должен быть любой символ.
    c В данной позиции должен быть любой символ, или ничего.

    Кроме того, в маске можно использовать различные разделители:

    Символы-разделители маски компонента TMaskEdit
    : Обычно применяется для разделения часов, минут, секунд.
    / Обычно применяется для разделения года, месяца, дня.
    - Обычно применяется для разделения цифр, например, в телефонных номерах.

    Примеры масок:

  • 999-99-99 (телефон)
  • 99/99/9999 (дата)
  • 00:00:00 (время)
  • 999999,00 р. (денежный формат)
  • Давайте укажем в строке "Маска ввода" маску телефона:

    000-00-00
            

    Использование нулей в качестве маски означает, что в этом месте обязательно должна быть цифра. Это разумно, ведь иначе номер телефона будет неполный, и мы не сможем дозвониться до абонента. Символы "-" служат разделителями, и добавляются автоматически. Введите маску, нажмите "ОК", сохраните проект и запустите его на исполнение. Теперь мы сможем вводить в маску только цифры. Причем если мы введем не все цифры, и попытаемся выйти из строки редактирования, сгенерируется ошибка. Нам придется либо вернуться и заполнить номер до конца, либо остановить программу, сбросив отладчик.

    В Редакторе масок помимо строки "Маска ввода" есть и другие строки. В строке "Символы для пробелов" мы можем указать символ, который будет выводиться маской в том месте, где пользователь должен будет что-то ввести. По умолчанию, это символ подчеркивания "_". Пользователь будет видеть пустую маску телефона, как

    ___-__-__
            

    Мы можем использовать и другие символы для заполнения пробелов.

    Ниже в Редакторе масок есть флажок "Сохранить литерал". Этот флажок включает или выключает возможность сохранения в тексте символов-разделителей. Если флажок включен, то в тексте сохранятся символы маски вместе с символами-разделителями, например:

    123-45-67
            

    Если флажок выключен, то в конечном тексте останутся только символы маски:

    1234567
            

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

    Итак, для нашего примера в строке "Маска ввода" укажите

    000-00-00
            

    В "Символы для пробелов" оставьте "_". Флажок "Сохранять литерал" пусть будет включен. Как только нажмете "ОК", свойство EditMask изменится, теперь в нем будет текст:

    000-00-00;1;_
            

    Как видите, значение этого свойства состоит из трех частей, разделенных точкой с запятой. Первая часть - это указанная нами маска. Во второй части может быть либо 0 (флажок "Сохранять литерал" выключен), либо 1 (флажок включен). В третьей части маски указывается символ для пробелов.

    Таким образом, мы могли бы и не пользоваться Редактором масок, а указать маску вручную. Например, введя значение

    00-00-0000 г.;1;_
            

    мы создадим маску, где пользователь будет обязан ввести все цифры месяца, дня и года, где в тексте сохранятся символы-разделители "-", и где на месте пробелов будет знак подчеркивания. В результате, мы получим дату, например в таком виде: "11-11-2013 г.".

    Страницы:

    Цель лекции

    Знакомство с символьными и строковыми типами данных, использование компонентов для работы со строками.

    Понятия "символ" и "строка"

    Для рядового пользователя эти понятия весьма абстрактны. Когда он вводит с клавиатуры "А", то считает это символом, буквой. Когда вводит "4", то это - цифра. А про всякие там пробелы, знаки препинания или арифметические знаки он и вовсе не думает. Но программист должен понимать, как все эти знаки воспринимаются компьютером. Поэтому наберитесь терпения, мы изучим эти понятия достаточно подробно.

    На самом деле, всё, что мы вводим с клавиатуры - это символы. Буква "z", цифра "3", пробел, знак умножить, знак процента и т.д. - всё это символы. Компьютер же может оперировать только цифрами, причем двоичными - такими, которые содержат лишь 0 или 1. Все эти буквы, десятичные цифры и прочие знаки для него не значат ровным счетом, ничего. И для того, чтобы мы могли как-то обрабатывать текст, цифры и прочую информацию, нужно было придумать специальную систему для перевода информации в понятную компьютеру, и обратно. Так появились кодовые страницы.

    Кодовая страница (англ. code page) - специальная таблица, сопоставляющая каждому значению байта некоторый символ.

    Не очень понятно? Давайте разбираться. Мы знаем, что информация измеряется байтами, и что в одном байте 8 бит. Бит - это минимальная единица информации, с которой может работать компьютер. В бите может храниться либо 0, либо 1.

    На заре развития компьютеров была разработана кодовая страница ASCII (англ. American Standard Code for Information Interchange - Американский кодовый стандарт для обмена информацией). Первая версия этого стандарта появилась в 1963 г. Эта страница содержала 7-ми битные символы, в каждом байте один бит был не задействован. Минимальное двоичное число, которое могло храниться в 7-ми битах - это ноль. Максимальное - 1111111.

    Нажмите кнопку "Пуск", выберите команду "Выполнить" и в окне "Запуск программы" укажите

    calc
        

    и нажмите <Enter>. Загрузится стандартный калькулятор Windows. В главном меню программы, в разделе "Вид" выберите "Инженерный". В левой части калькулятора, ниже поля ввода чисел, вы увидите переключатели различных систем исчисления:

    (рис 5.1) Переключатели калькулятора

    Здесь мы имеем возможность переключаться на четыре системы исчисления:

  • Hex - 16-ричная. Используется в основном, в языке Ассемблере или при отладке программ.
  • Dec - 10-тичная. Наша обычная система, используется по умолчанию.
  • Oct - 8-ричная. Почти не используется.
  • Bin - 2-ичная. Хоть она и является для компьютера единственно понятной, но вследствие громоздкости записей, в программировании её обычно не применяют.
  • Давайте посмотрим, сколько символов могло содержаться в кодовой странице ASCII. Переключитесь на двоичную систему (Bin), введите 7 единиц, затем переключитесь обратно на десятичную систему (Dec). У нас получилось 127. Именно столько символов содержалось в первой ASCII таблице. Помимо латинских букв, таблица содержала и другие символы - цифры, арифметические знаки, знаки препинания, символы пробела, скобки и т.п. Каждому символу соответствовал собственный номер в таблице. Если мы вводили английскую букву "A", то в компьютер попадал номер этого символа в таблице - 65. Или, в двоичном виде, 100 0001. Таким образом, символы можно было сравнивать между собой. Английское "B" находилось под номером 66 и, следовательно, было больше, чем "A". Строчные буквы имели другие номера, например, "a" шла в таблице под номером 97 и считалась большей, чем "A". Мы вводим символы, которые автоматически преобразовываются в цифры, с которыми уже оперирует компьютер.

    Тут нужно сделать одно важное пояснение. Если мы вводили число "65", то для ПК это не было числом 65, или латинской буквой "A", это было двумя символами "6" и "5". Символу "6" соответствует номер 54 кодовой таблицы, а символу "5" - номер 53. Таким образом, числа, которые мы вводим в ПК, на самом деле не числа, а текстовые символы! Преобразования таких символов в числа и обратно обычно производятся программой автоматически. Такие преобразования, например, постоянно выполняет стандартный калькулятор Windows. А когда мы будем изучать числа, нам самим придется выполнять такие же преобразования.

    Всё бы хорошо, но помимо английского языка, в мире существует множество других языков! Мы, например, пишем кириллицей - русским начертанием символов. 127 символов было явно недостаточно, чтобы можно было вводить текст и на других языках. Поэтому таблица ASCII развивалась, из года в год появлялись новые стандарты. Каждый символ стал уже 8-ми битным. Посмотрите на калькуляторе - восемь бит могут содержать максимальное число 1111 1111, при переводе в десятичную систему мы получим 255 символов. Первая половина таблицы оставалась неизменной, зато вторую половину таблицы можно было задействовать для символов других языков и псевдографики, с помощью которой программисты времен MS-DOS рисовали окошки, панельки, таблицы и меню. Однако и этого было слишком мало, чтобы закодировать символы всех языков на Земле. Для каждого языка приходилось разрабатывать свой стандарт, несовместимый с другими. Причем, для одного языка могло быть разработано несколько стандартов! Для русского языка, например, имеются стандарты CP866 (Code Page 866), KOI8-R, KOI8-U, ISO-8859-5, и это только самые распространенные! В хаосе стандартов надо было как-то разбираться, совершенствовать их.

    На смену ASCII пришла кодировка ANSI (англ. American National Standards Institute - Американский Национальный Институт Стандартов). Так, в MS Windows кодовая страница ANSI, содержащая кириллицу - это Windows-1251 (или CP1251), которая появилась в 1990-1991 гг.

    Однако и этого было недостаточно, ведь для каждого языка по-прежнему требовалась собственная кодировка, а языков на Земле много. Назрела необходимость переходить к "широким" стандартам, в которых символ занимает более одного байта. Так, в 1991 г. был предложен стандарт Юникод (англ. Unicode) - универсальная система кодирования символов, представляющая знаки практически всех языков. В этом стандарте в одном документе можно использовать символы кириллицы, китайские или японские иероглифы, знаки математических формул, музыкальные знаки и т.п.

    Первая версия Юникода имела фиксированный размер символов 2 байта (16 бит). В одной кодировке уже можно было использовать 65 535 символов! Однако оказалось, что и этого недостаточно. Юникод получил дальнейшее развитие, и из года в год стали появляться новые версии и стандарты, основанные на Юникоде. Имеются такие стандарты, как UTF-8 (англ. Unicode Transformation Format, 8 bit - 8-ми битный формат преобразования Юникода), UTF-16, UTF-32.

    В Lazarus, в основном, используется формат UTF-8, так что разберем его. UTF-8 появился 2 сентября 1992 года. Основное его отличие от первоначального Unicode в том, что в UTF-8 символы имеют не фиксированный размер! Если используются символы с номером меньшим, чем 128, то они занимают 1 байт, как обычный ASCII-текст. Символы с номером от 128 и больше могут занимать от 2 до 6 байт (реально максимальный размер символа - 4 байта, т.к. в Юникоде нет символов с большим номером). Символы кириллицы занимают, например, по 2 байта. Так что цепочка символов в 5 байт в UTF-8 не всегда означает строку из пяти символов.

    Такой подход делает UTF-8 самой экономичной кодировкой для совместимости со старыми стандартами, однако есть и минусы. К сожалению, для русскоязычных (и вообще для всех не англоязычных) пользователей Windows в Lazarus придется столкнуться с некоторыми проблемами применения различных кодировок: в Lazarus используется кодировка UTF-8, ОС Windows использует UTF-16, а в консольных приложениях Windows используется системная кодировка CP866 (то есть, стандарт ANSI). Её же используют некоторые функции компилятора FPC. Так что в некоторых случаях нам придется пользоваться функциями преобразования кодировок, например, UTF8ToConsole(), CP866ToUTF8() и т.п. Мы познакомимся с ними позже, в свое время.

    Итак, подведем некоторые итоги.

  • Символ - это графическое изображение буквы, цифры, арифметического знака, знака препинания или какого-либо другого знака, отвечающее какому-либо стандарту кодировки символов.
  • Каждому символу соответствует его номер в кодовой таблице символов.
  • Кодировок (code page) существует множество.
  • Строка - это цепочка символов.
  • Цифры, которые мы набираем на клавиатуре - это символы. Чтобы обрабатывать их, как цифры, программа выполняет автоматическое преобразование из символов в цифры, и обратно, когда выводит нам результаты вычислений.
  • UTF-8 - это одно из представлений Юникода, используемое в Lazarus.
  • В одной строке могут встречаться символы, которые занимают 1, 2 или даже больше байт.
  • Символьные типы данных

    В Lazarus имеется символьный тип Char. Переменная такого типа занимает ровно один байт памяти и может содержать любой ASCII - символ. Русскому языку с этим типом не повезло - поскольку символы кириллицы занимают по 2 байта, использовать этот тип с русскими буквами нельзя. Давайте откроем Lazarus с новым проектом. Если Lazarus у вас уже загружен, закройте старый проект командой Файл -> Закрыть, и создайте новый проект командой Проект -> Создать проект -> Приложение. Сразу же сохраните проект в папку 05-01 там, где вы храните все проекты лекций, проекту дайте имя MyStrings, и не забудьте назвать модуль главной формы Main, а саму форму fMain. Пусть это войдет у вас в привычку. Как всё это делается, вы должны знать по предыдущим лекциям. Не вздумайте давать своим проектам имена, используя ключевые (зарезервированные) слова. Например, нельзя давать проекту или модулю имя Strings, поскольку это слово зарезервировано, но MyStrings можно.

    Прямо посреди формы установите кнопку TButton, дважды нажмите на нее, чтобы сгенерировать обработчик OnClick. В обработчике создадим раздел переменных var, укажем там одну переменную типа Char, и запрограммируем следующий код:

    procedure TfMain.Button1Click(Sender: TObject);
    var
      ch1: Char; //переменная символьного типа
    begin
      ch1:= 'Z';
      ShowMessage(ch1);
    end;
        

    Как видим, здесь мы переменной ch1 присвоили значение - символ "Z". Запомните правило:

    Символы и строки в Lazarus должны быть заключены в одинарные кавычки. Если требуется ввести в текст одинарную кавычку (например, в слове can't), то следует указать две таких одинарных кавычки, которые также заключены в одинарные кавычки.

    Например:

    Mystring:= 'I can' + '''' + 't';
        

    Этот пример выполнять не нужно, он просто демонстрирует использование кавычек в строковых выражениях, и возможность в выражении соединять несколько строк в одну с помощью знака "+". Однако вернемся к нашему проекту. После того, как мы присвоили символьной переменной большую английскую букву "Z", мы вывели содержимое переменной с помощью строки

    ShowMessage(ch1);
        

    Сохраните проект, скомпилируйте его и выполните. Когда программа с кнопкой появится на экране, нажмите нашу единственную кнопку - выйдет сообщение с буквой "Z":

    (рис 5.2) Вывод символа

    Таким образом, мы можем работать с отдельными символами. Однако если вы исправите код, и вместо буквы "Z" в строке

    ch1:= 'Z';
        

    укажете русский символ, то при попытке скомпилировать и запустить проект выйдет ошибка "Error: Incompatible types: got "Constant String" expected "Char"" - несовместимость типов String (строка) и Char (символ). Поскольку русские буквы занимают по два байта, Lazarus их считает строкой символов. Однако это не значит, что мы совсем не имеем возможности работать с отдельными символами кириллицы.

    Ранее упоминалось, что в Lazarus используется формат UTF8. Для поддержки этого формата были разработаны расширенные типы данных, в том числе и символьные. Так, имеется тип TUTF8Char, который позволяет работать с любыми отдельными символами, в том числе и русскими. Имеет смысл всегда использовать его вместо стандартного Char. Но для этого нам нужно будет подключить модуль LCLType, где этот тип описан.

    Перейдите в редактор кода и пролистайте код модуля вверх. Там вы увидите раздел uses (англ. use - использовать), где перечислены подключенные модули. Нам нужно поставить после последнего модуля запятую и добавить наш подключаемый модуль:

    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
      LCLType;
        

    Если строка получается длинной, то после запятой можно переносить текст на другую строку.

    Теперь вернемся к обработчику нажатия на кнопку и переделаем его:

    procedure TfMain.Button1Click(Sender: TObject);
    var
      ch1: Char;
      ch2: TUTF8Char;
    begin
      ch1:= 'Z';
      ch2:= 'Я';
      ShowMessage(ch1);
      ShowMessage(ch2);
    end;
        

    Теперь всё сработает как надо, и русский символ "Я" выйдет так же, как английский "Z".

    Однако, это еще не всё. Символы можно вводить, указывая их номер в таблице символов. Для этого перед номером нужно указать символ "#", например:

    ch1:= #90;
        

    Под номером 90 находится буква Z в таблице символов, так что результат не изменится. Также в строковых выражениях можно указывать и специальные символы. Например, символ под номером 13 - это символ перехода на другую строку. Давайте снова немного изменим код:

    procedure TfMain.Button1Click(Sender: TObject);
    var
      ch1: Char;
      ch2: TUTF8Char;
    begin
      ch1:= #90;  //буква Z
      ch2:= 'Я';
      ShowMessage(ch1 + #13 + ch2); //вывод двухстрочного сообщения
    end;
        

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

    Строковые типы данных

    В Lazarus основным строковым типом является String (англ. string - строка). На форму нашего проекта разместите еще одну кнопку. Её обработчик будет выглядеть так:

    procedure TfMain.Button2Click(Sender: TObject);
    var
      s: String;
    begin
      s:= 'Это строка из пяти слов!';
      ShowMessage(s);
    end;
        

    Как видите, поскольку строка в Lazarus имеет формат UTF8, то никаких особых ухищрений для работы со строками тут не нужно, в переменную типа String можно записать любой, в том числе и русский текст. Размер строки String неограничен, однако имеется возможность жестко задать размер. Такой способ используется, когда вы точно знаете, что больше данного размера строка не будет. В этом случае размер указывается после ключевого слова String в квадратных скобках, например:

    var
      MyStr: String[50];
        

    В переменную MyStr можно записать до 50 символов. Максимальный размер строки, который можно жестко задать таким способом - 255 символов. Однако имеются в виду символы ASCII, то есть английские, однобайтовые. Пример:

    var
      s: string[7];
    begin
      s:= 'Привет!';
      ShowMessage(s);
    end;
        

    Данный пример ошибки не вызовет, однако сообщение выйдет не полностью, а обрезанным: "При". То есть, три первых буквы заняли 6 байт, четвертая уже не уместилась. В данном случае будет правильным указать размер не 7, а 14 - по удвоенному количеству букв. Впрочем, на практике обычно применяют тип String без ограничений, в этом случае строка обрабатывается правильно.

    Имейте в виду, что тип String является динамичным, то есть, заранее память для него не выделяется. Строго говоря, выделяется память на указатель строки, а не на саму строку. Физически строке выделяется необходимая память только в момент присвоения ей какого-то значения. Однако нередко возникает необходимость очистить такую строку. Для этого достаточно присвоить ей пустые кавычки, без пробелов и без каких-либо других символов:

    s:= '';
        

    В этом случае, строке присваивается значение Nil, то есть ноль, ничего, и строка становится пустой.

    Строковой переменной можно присваивать значения символьных переменных или констант, например:

    var
      c: Char;
      s: String;
    begin
      c:= 'Z';
      s:= c;
        

    Помимо String в Lazarus есть и другие строковые типы.

    ShortString Короткая строка, которая может содержать максимум, 255 ASCII-символов. То есть, ShortString - это String[255].
    AnsiString Строка неограниченной длины из ANSI-символов. Фактически всё, что мы говорили про String, относится именно к AnsiString. Отдельного типа String как такового, не существует, это просто сокращенная запись AnsiString. Однако это зависит от настроек. Есть в Паскале такие переключатели, которые еще называют директивы компилятора. Такие директивы подобно комментариям, заключают в фигурные скобки, а первым символом должен быть символ доллара. Тип, который будет использован в качестве String, зависит от директивы {$H}. Если она выключена {$H-}, то при указании типа String будет подразумеваться тип ShortString. Если она включена {$H+} - то AnsiString. По умолчанию переключатель включен, вы сможете это увидеть в третьей строке модуля, пролистав его код вверх:
    unit Main;
    
    {$mode objfpc}{$H+}
            

    На практике короткую строку используют крайне редко, ведь если нужна короткая строка, то ее размер можно указать явно. Поэтому данный переключатель исправлять вручную обычно не приходится. Давайте считать, что String и AnsiString - это одно и то же.

    PChar Строка в стиле C/C++ с нулевым символом в конце. Такой тип строк используется в функциях Windows API, поэтому имеет поддержку и в Lazarus. Что это за строка такая? Дело в том, что обычные строки динамические, то есть фактически переменная типа String - это указатель на строку. Эта переменная хранит физический адрес строки в памяти, и количество занимаемых ею байт. Строка типа PChar устроена несколько иначе. Это тоже указатель на строку, но он не хранит её размер. А как тогда компилятору знать, сколько байт нужно считывать при обращении к такой переменной? Дело в том, что в строках типа PChar завершающим всегда будет нулевой символ, то есть, символ #0. Если такой символ поместить внутри строки, то компилятор не будет читать всю строку. Встретив символ #0, он решит, что строка закончена. Мы будем использовать PChar, когда дойдем до функций WinAPI.

    Как правило, строкам одного типа можно присваивать значения строк другого типа, компилятор автоматически преобразует текст. Исключение составляют строки PChar, тут нам придется делать преобразование вручную, с помощью функции PChar(). Исправим обработчик второй кнопки:

    procedure TfMain.Button2Click(Sender: TObject);
    var
      s1: String; //он же AnsiString
      s2: ShortString;
      s3: PChar;
    begin
      s1:= 'Это строка из пяти слов!';
    
      //Теперь присвоим тот же текст в ShortString:
      s2:= s1;
    
      //Тот же текст в PChar. Для преобразования строки в этот тип
      //используем функцию PChar():
      s3:= PChar(s1);
    
      //Соберем сообщение из трех разнотиповых строк. Каждый тип
      //выведем в отдельной строчке:
      ShowMessage(s1 + #13 + s2 + #13 + s3);
    end;
        

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

    Имеются еще типы UnicodeString и WideString, оба типа содержат двухбайтовые символы. Но работать с такими типами неудобно - возникают проблемы с кириллицей, для нас гораздо удобней простой String. Поэтому рассматривать данные типы мы не будем.

    Резюмируем некоторые положения:

  • Три основных строковых типа: AnsiString, ShortString и PChar.
  • Обычно указывают тип String. Если переключатель {$H} включен (по умолчанию), то используется тип AnsiString. Иначе - ShortString.
  • Строке можно присвоить либо текст, заключенный в одинарные кавычки, либо содержимое другой строковой переменной, например:
  • s1:= 'Текст';
    s2:= s1;
        
  • Строке типа PChar можно присвоить либо текст, либо содержимое другой строковой переменной. Но если тип этой переменной отличается, то нужно сделать преобразование функцией PChar():
  • var
      s: String;
      pc: PChar;
    begin
      s:= 'Текст';
      pc:= 'Текст'; //присвоили текст
      pc:= PChar(s); //присвоили преобразованное значение переменной s
        

    Компоненты для ввода строк

    Теперь мы знаем, что такое строки, самое время разобрать способы предоставления пользователю возможностей эти самые строки вводить в нашу программу. Помните второй проект второй лекции? Там мы предлагали пользователю ввести свое имя, которое затем использовали в приветствии. Для этого мы использовали компонент TEdit. Разберем его возможности, и познакомимся с другими аналогичными компонентами.

    Для этого закройте старый проект и создайте новый. Как всегда, главную форму назовите fMain, и сохраните проект. При этом проекту дайте имя EditControls (контролами программисты между собой называют компоненты, с помощью которых программа взаимодействует с пользователем), а модуль этой формы назовите Main. Проект сохраните в папку 05-02 там, где у нас хранятся все остальные проекты.

    Компонент TEdit

    На форму установите компонент TEdit (если не помните, где он находится, смотрите рис. 2.5 в лекции №2). По умолчанию, он имеет ширину 80 пикселей (свойство Width), увеличьте его до 200. Теперь давайте разбираться с основными свойствами этого компонента, которые могут нам понадобиться, для этого он должен быть выделен.

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

    Align Выравнивание компонента. С этим свойством мы уже знакомы, оно позволяет компоненту занять весь верх, низ, левую или правую сторону, или же всю форму или панель, на которой компонент находится. В компоненте TEdit это свойство тоже есть, но применяется очень редко - трудно придумать ситуацию, в которой этот компонент потребуется таким образом выровнять. Обычно это свойство не трогают. Значения этого свойства должны быть вам знакомы по лекции №3.
    Alignment Выравнивание текста. Вот это свойство используется чаще. Оно позволяет выровнять текст в компоненте по центру, по левому или правому краю. Как выравнивать текст, обычно каждый решает для себя сам, но есть некоторые рекомендации: простой текст выравнивают обычно по левому краю, цифры - по правому, а такие данные, как дата-время можно выровнять по центру. Итак, значения этого свойства:
  • taCenter - по центру.
  • taLeftJustify - по левому краю. Это значение используется по умолчанию.
  • taRightJustify - по правому краю.
  • Anchors Привязка компонента к краям формы или панели, на которой компонент находится. С этим свойством вы также знакомы по третьей лекции.
    AutoSelect Автоматическое выделение текста. Если свойство равно True (по умолчанию), то когда компонент становится активным, выделенным, или как говорят, получает фокус ввода, текст в компоненте, если он есть, автоматически выделяется. Иначе текст будет невыделен.
    CharCase Регистр символов текста в компоненте. Может иметь следующие значения:
  • ecLowerCase - Все символы строчные (обычные), даже если набирать текст с нажатой клавишей <Shift> или с включенной <Caps Lock>.
  • ecNormal - Обычный текст, в котором могут быть и строчные, и прописные символы. Используется по умолчанию.
  • ecUpperCase - Все символы прописные (заглавные).
  • Color Позволяет выбрать цвет фона в компоненте.
    Font Позволяет выбрать шрифт, используемый в компоненте. Вообще каждый решает сам, как будет выглядеть дизайн его программы, однако желательно для всех компонентов использовать один и тот же шрифт. Если вас не устраивает шрифт по умолчанию, поменяйте его для всей формы, и он автоматически будет использоваться для всех компонентов, которые вы на этой форме установите! Если же в вашем проекте будет много форм, то выработайте для них какие-то одни стандарты (шрифт, цвет фона, обрамление и т.п.), и придерживайтесь их во всех формах.
    Hint Текст подсказки, который будет всплывать, когда пользователь подведет к компоненту указатель мыши.
    MaxLength Максимальный размер текста в символах. По умолчанию равен нулю, что снимает ограничение в размерах. Если текст не умещается в поле ввода, он будет прокручиваться. Ограничение на количество символов иногда бывает необходимо, например, если текст будет записан в базу данных или запись, которые имеют фиксированный размер строки. Во всех остальных случаях свойство можно не изменять.
    PasswordChar Символ, скрывающий пароль при вводе. Очень интересное свойство. Должно быть, всем приходилось когда-то вводить пароль. И обычно вместо нужных букв и цифр в этом поле отображались звездочки или кружочки. На самом деле, текст остается неизменным, но он прячется от тех, кто может оказаться у вас за спиной и подсмотреть ваш пароль. Реализуется эта возможность как раз данным свойством. Здесь нужно указать номер символа в таблице символов. По умолчанию, это #0 - нулевой символ, означающий, что текст выводится, как есть. Но можно поставить и другой символ, причем указать именно символ, а не его номер. Давайте в этом свойстве укажем символ "*". Как только вы нажмете <Enter>, сразу же изменится и свойство EchoMode - оба эти свойства взаимосвязаны. Мы разберем его чуть ниже, а пока сохраните проект и запустите на выполнение. Теперь любой текст, включая пробелы и другие знаки, будет выводиться на экран в виде звездочек. Однако это не все.

    Мы имеем возможность маскировать пароль и другими символами. Выделите компонент TEdit и измените его свойство Font, выбрав там шрифт Wingdings (если у вас ОС Windows). Это тот редкий случай, когда имеет смысл выбрать другой шрифт для отдельного компонента. Теперь нам нужно выбрать символ. Откройте редактор MS Word. Там выполните команду Вставка -> Символ:

    (рис 5.3) Определение кода символа

    В поле "Шрифт" выберите Wingdings, затем выберите подходящий символ, например, книгу. Потом посмотрите код выбранного знака, в данном случае это 38. Нажмите "Отмена" и закройте MS Word - он нам больше не нужен. Теперь вернитесь к проекту и в свойстве PasswordChar укажите #38 - код выбранного нами знака. Когда нажмете <Enter>, то значение #38 изменится на - не обращайте внимание. Сохраните проект и запустите его на выполнение - текст будет скрываться за пиктограммой книги. Используя различные шрифты, вы можете подобрать для себя и другие подходящие символы.

    EchoMode Тип сообщения. Связан с PasswordChar, и обычно устанавливается автоматически, но можно установить его и вручную. Имеет следующие значения:
  • emNone - вместо символов выводятся пробелы. Сам текст не меняется.
  • emNormal - обычный тип, используется по умолчанию. Устанавливается, если в PasswordChar установлено значение #0.
  • emPassword - тип пароля. Устанавливается, если в PasswordChar вы укажете другое значение, не #0. Сам текст не меняется.
  • ReadOnly Только для чтения. Разрешает или запрещает пользователю ввод текста. Если False, то пользователь может и читать, и вводить текст, иначе он может только читать его. Однако в любом случае вы можете менять там текст программно. Позже мы разберем такую возможность.
    Text Основное свойство этого компонента. Содержит текст, введенный пользователем, или установленный в компоненте программно. Причем даже если вы его скроете, как пароль, сам текст меняться не будет. К этому свойству можно относиться, как к строковой переменной, которую может изменять пользователь. По умолчанию, в это свойство сразу же прописывается имя компонента, в нашем случае, edit1. На практике такой текст вряд ли понадобится, поэтому программист обычно очищает это свойство. Очистите его и вы. Как только для подтверждения нажмете <Enter>, текст в компоненте на форме исчезнет.

    Остальные полезные свойства должны быть вам знакомы по предыдущим лекциям. Итак, установите для компонента Edit1 шрифт Times New Roman, размер шрифта пусть будет 11. В свойстве PasswordChar пусть будет значение по умолчанию - #0. Свойство Text очищено, а свойство ReadOnly установлено в True. Теперь ниже TEdit установите кнопку, сгенерируйте для нее обработчик нажатия, и введите там следующий код:

    procedure TfMain.Button1Click(Sender: TObject);
    begin
      Edit1.Text:= 'Привет!';
    end;
            

    Здесь мы программно меняем текст в компоненте. Для этого мы обращаемся к нему по имени - Edit1, после чего ставим точку. Обратите внимание - если поставить точку и чуть подождать, всплывет окошко со всеми свойствами, методами и событиями, которые мы можем использовать. Нам нужно свойство Text. Как только мы введем первую "T", список отфильтруется, оставив там только команды на букву "T". Как только мы введем следующую букву "e", то в списке останется только одно подходящее свойство - "Text". То, что нужно. Можно просто нажать <Enter>, не вводя остальных символов, и свойство само вставится в код. Причем вместе с последующим оператором присваивания. Мелочь, а приятно. Останется только указать строку, которую мы хотим присвоить.

    Таким образом, можно менять программно многие (но не все) свойства компонентов, их размеры и положение, текст и цвет, и многое другое. Сохраните проект и запустите его на выполнение. Если вы все сделали правильно, то пользователь не сможет вписывать текст в Edit1, а при нажатии кнопки Button1, текст там поменяется программно. Теперь давайте чуть изменим команду присваивания:

    Edit1.Text:= Edit1.Text + 'Привет! ';
            

    С выражениями мы уже работали, так что тут трудностей быть не должно. Мы просто берем текст, который уже был в свойстве Text (при первом нажатии там будет пустая строка), и прибавляем к нему строку 'Привет! ' - не забудьте после восклицательного знака поставить пробел, чтобы текст не слипался друг с другом. Сохраните проект и запустите его. Нажимая кнопку, мы сможем многократно добавлять слово 'Привет! ' в компонент.

    Компонент TLabelEdit

    На вкладке Additional Палитры компонентов есть странный компонент TLabelEdit:

    (рис 5.4) Компонент TLabelEdit

    Установите его на свободное место на форму, и посмотрите на его свойства в Инспекторе объектов. В общем-то, это гибрид метки TLabel и текстового поля TEdit. Свойства почти все знакомы, но есть и некоторые различия.

    EditLabel - раскрывающее свойство, внутри которого находится свой набор подсвойств для метки. Слева от этого свойства мы видим кнопку "+", щелкнув по которой раскроем подсвойства. Здесь нам понадобится, прежде всего, свойство Caption, в котором мы можем записать текст метки. Этот текст будет пояснять назначение текстового поля. Напишем в этом свойстве Фамилия, текст метки изменится, а пользователь сразу поймет, что сюда он должен будет вписать свою фамилию:

    (рис 5.5) Компонент TLabelEdit в Инспекторе объектов и в Редакторе форм

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

    LabelPosition - местонахождение метки. Может быть:

  • lpAbove - сверху текстового поля. Это значение по умолчанию.
  • lpBelow - снизу текстового поля.
  • lpLeft - слева
  • lpRight - справа
  • LabelSpacing - расстояние в пикселях между меткой и текстом. По умолчанию равно 3 пикселя. Изменяя это значение, можно приближать метку к полю или отодвигать ее.

    В остальном, этот компонент почти полностью идентичен обычному TEdit.

    TLabelEdit будет полезен при создании форм, где пользователь должен вписывать различные данные, для этого раньше применялись отдельно TLabel и TEdit. Данный гибрид, безусловно, удобней.

    Компонент TMaskEdit

    На той же вкладке Additional находится еще один полезный компонент для ввода строк - TMaskEdit:

    (рис 5.6) Компонент TMaskEdit

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

    Установите TMaskEdit на форму и посмотрите на его свойства в Инспекторе объектов. В принципе, все свойства нам знакомы. Интерес вызывает лишь одно свойство EditMask. Это сложное раскрывающееся свойство, то есть, щелкнув по кнопке с тремя точками правее свойства, можно его раскрыть:

    (рис 5.7) Раскрывающееся свойство EditMask

    Когда оно раскрыто, мы видим следующую картину:

    (рис 5.8) Редактор масок

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

    Символы маски компонента TMaskEdit
    0 В данной позиции должна быть цифра. Если пользователь введет не все цифры маски, будет создана исключительная ситуация, и он не сможет продолжать работу, не заполнив все положенные цифры. Если такая ситуация возникла у вас во время тестового выполнения программы, можете закрыть программу командой "Запуск->Сбросить отладчик".
    9 В данной позиции может быть либо цифра, или ничего.
    # В данной позиции может быть знак "+", "-", цифра, или ничего.
    L В данной позиции должна быть буква.
    l В данной позиции должна быть буква или ничего.
    A В данной позиции должна быть буква или цифра.
    a В данной позиции должна быть буква или цифра, или ничего.
    C В данной позиции должен быть любой символ.
    c В данной позиции должен быть любой символ, или ничего.

    Кроме того, в маске можно использовать различные разделители:

    Символы-разделители маски компонента TMaskEdit
    : Обычно применяется для разделения часов, минут, секунд.
    / Обычно применяется для разделения года, месяца, дня.
    - Обычно применяется для разделения цифр, например, в телефонных номерах.

    Примеры масок:

  • 999-99-99 (телефон)
  • 99/99/9999 (дата)
  • 00:00:00 (время)
  • 999999,00 р. (денежный формат)
  • Давайте укажем в строке "Маска ввода" маску телефона:

    000-00-00
            

    Использование нулей в качестве маски означает, что в этом месте обязательно должна быть цифра. Это разумно, ведь иначе номер телефона будет неполный, и мы не сможем дозвониться до абонента. Символы "-" служат разделителями, и добавляются автоматически. Введите маску, нажмите "ОК", сохраните проект и запустите его на исполнение. Теперь мы сможем вводить в маску только цифры. Причем если мы введем не все цифры, и попытаемся выйти из строки редактирования, сгенерируется ошибка. Нам придется либо вернуться и заполнить номер до конца, либо остановить программу, сбросив отладчик.

    В Редакторе масок помимо строки "Маска ввода" есть и другие строки. В строке "Символы для пробелов" мы можем указать символ, который будет выводиться маской в том месте, где пользователь должен будет что-то ввести. По умолчанию, это символ подчеркивания "_". Пользователь будет видеть пустую маску телефона, как

    ___-__-__
            

    Мы можем использовать и другие символы для заполнения пробелов.

    Ниже в Редакторе масок есть флажок "Сохранить литерал". Этот флажок включает или выключает возможность сохранения в тексте символов-разделителей. Если флажок включен, то в тексте сохранятся символы маски вместе с символами-разделителями, например:

    123-45-67
            

    Если флажок выключен, то в конечном тексте останутся только символы маски:

    1234567
            

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

    Итак, для нашего примера в строке "Маска ввода" укажите

    000-00-00
            

    В "Символы для пробелов" оставьте "_". Флажок "Сохранять литерал" пусть будет включен. Как только нажмете "ОК", свойство EditMask изменится, теперь в нем будет текст:

    000-00-00;1;_
            

    Как видите, значение этого свойства состоит из трех частей, разделенных точкой с запятой. Первая часть - это указанная нами маска. Во второй части может быть либо 0 (флажок "Сохранять литерал" выключен), либо 1 (флажок включен). В третьей части маски указывается символ для пробелов.

    Таким образом, мы могли бы и не пользоваться Редактором масок, а указать маску вручную. Например, введя значение

    00-00-0000 г.;1;_
            

    мы создадим маску, где пользователь будет обязан ввести все цифры месяца, дня и года, где в тексте сохранятся символы-разделители "-", и где на месте пробелов будет знак подчеркивания. В результате, мы получим дату, например в таком виде: "11-11-2013 г.".

    Вернуться к учебному плану