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

Стандартные строковые функции и сообщения

Показывать лекцию целиком

Цель лекции

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

Функции для работы со строками

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

А для того, чтобы посмотреть работу функций на практике, создадим новое приложение. Это будет простое приложение с единственной кнопкой посреди окна. Сохраните проект в папку 06-01, поскольку проект будет совсем простой, имена модуля и проекта можно оставить без изменений. Сгенерируйте событие нажатия на кнопку, в этом событии мы и будем экспериментировать над строками.

Объединение (конкатенация) строк

Программисту довольно часто приходится в коде объединять несколько строк в одну. Мы уже делали подобное объединение в прошлых лекциях. Для объединения служит оператор "+":

string_1 + string_2 + …string_n;
    

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

procedure TForm1.Button1Click(Sender: TObject);
var
  s1: String;
begin
  s1:= 'Строка №1' + #13 + 'Строка №2' + #13 + 'Строка №3';
  ShowMessage(s1);
end;
    

Здесь, в переменной s1 мы собрали строку из 5 кусочков, причем два из них - символы перехода на новую строку. Сохраните проект, скомпилируйте его и убедитесь, что полученное сообщение будет трехстрочным.

Функция Concat() делает то же самое - объединяет строки. Её синтаксис такой (в квадратные скобки принято помещать необязательные параметры функций):

Concat(S1 [, S2,…Sn]);

Здесь S1, S2 и т.д. - строки. Предыдущий пример можно было бы записать и так:

  s1:= Concat('Строка №1', #13, 'Строка №2', #13, 'Строка №3');
    

Длина строки

Поскольку мы предоставляем пользователям возможность вводить различные строки, нередко возникает необходимость выяснить длину этих самых строк. Для этого существует функция Length(). Её синтаксис:

Length(S);
    

где S - строка. Функция возвращает нам размер количество символов в этой строке. Однако в Lazarus не все так просто. Давайте изменим предыдущий код обработчика кнопки на следующий:

procedure TForm1.Button1Click(Sender: TObject);
var
  s1: String;
begin
  s1:= 'Hello';
  ShowMessage(IntToStr(Length(s1)));
end;
    

Поскольку результатом работы функции Length() будет целое число - количество символов, то для вывода этих данных на экран нам приходится преобразовать полученное число в строковый тип, что мы и делаем в коде

ShowMessage(IntToStr(Length(s1)));
    

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

  • Length() - вычисление размера строки s1.
  • IntToStr() - преобразование полученного в №1 результата из целого числа в строку.
  • ShowMessage() - вывод преобразованного в №2 результата на экран.
  • Если вы откомпилируете проект и запустите его на выполнение, то получите результат: 5. Столько символов в строке "Hello". Однако измените эту строку на "Привет" и снова выполните программу:

      s1:= 'Привет';
      ShowMessage(IntToStr(Length(s1)));
        

    Мы ожидаем получить число 6 - количество символов в слове "Привет", но неожиданно получаем 12! Дело в том, что функция работает с ANSI-строками, то есть с теми, что занимают по 1 байту на символ. А кириллица - это не ANSI а UTF8, и требует по 2 байта на символ! Как быть? В подобных случаях используйте UTF8-аналоги строковых функций. То есть, вместо Length() используйте UTF8Length(). Эта функция гарантированно вернет количество символов в строке, на каком бы языке эти символы не вводились. Но для использования UTF8Length() нужно подключить модуль LCLProc, где и реализованы все UTF8-функции.

    Пролистайте код выше, на начало модуля, и добавьте LCLProc в раздел uses:

    (рис 6.1) Добавление модуля в раздел uses

    Теперь мы можем изменить наш обработчик:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      s1: String;
    begin
      s1:= 'Привет';
      ShowMessage(IntToStr(UTF8Length(s1)));
    end;
        

    Вот теперь мы получим в результате число 6.

    Таким образом, если вы точно знаете, что будете иметь дело только с английскими символами, то для определения количества символов в строке, и занимаемых этой строкой байт, используйте функцию Length(). Во всех остальных случаях Length() можно использовать для получения размера строки в байтах, а UTF8Length() - для получения количества символов в строке.

    Поиск в строке

    Иногда необходимо выяснить, есть ли в строке нужный текст. Для этого служат функции

  • Pos() - для ANSI-символов
  • UTF8Pos() - для кириллицы (UTF8-символы) - требует подключения модуля LCLProc
  • Их синтаксис:

    Pos(Substr, Str);
    UTF8Pos(Substr, Str);
        

    Здесь Substr - искомый текст; Str - строка, в которой ищется текст. Функции возвращают в качестве результата целое число. Если искомый текст в строке отсутствует, обе функции вернут ноль. Иначе - номер символа строки, с которого начинается найденная подстрока. Переделаем код обработчика кнопки (модуль LCLProc у нас уже подключен):

    procedure TForm1.Button1Click(Sender: TObject);
    var
      s1: String;
    begin
      s1:= 'Привет';
      ShowMessage(IntToStr(UTF8Pos('ив', s1)));  //результат: 3
    end;
        

    Запустив программу на выполнение, убедимся, что функция

    UTF8Pos('ив', s1)
        

    возвращает результат 3 - номер первого символа искомой подстроки в строке "Привет".

    Если в строке содержится несколько искомых подстрок, функции вернут номер первого такого вхождения. А если для строки с русскими буквами использовать функцию Pos() вместо UTF8Pos(), результат будет неверный.

    Получение подстроки

    Чтобы из строки получить ее часть (подстроку), применяют функции

  • Copy() - для ANSI-символов
  • UTF8Copy() - для кириллицы - требует подключения модуля LCLProc
  • Их синтаксис:

    Copy(Str, StartCharIndex, Count);
    UTF8Copy(Str, StartCharIndex, Count);
        

    Здесь Str - строка исходного текста; StartCharIndex - номер первого символа подстроки; Count - количество символов подстроки. Снова переделаем обработчик кнопки:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      s1: String;
    begin
      s1:= 'Привет';
      ShowMessage(UTF8Copy(s1, 3, 2));
    end;
        

    В результате выполнения программы вы убедитесь, что

    UTF8Copy(s1, 3, 2)
        

    из строки "Привет" вернет "ив" - подстроку, начиная с третьего символа, размером два символа.

    Если для кириллицы вместо UTF8Copy() использовать Copy(), результат будет неверным.

    Удаление части строки

    Для удаления части строки применяют функции Delete() и UTF8Delete().

    Их синтаксис:

    Delete(Str, StartCharIndex, Count);
    UTF8Delete(Str, StartCharIndex, Count);
        

    Здесь Str - строка исходного текста; StartCharIndex - номер первого символа удаляемой подстроки; Count - количество удаляемых символов. Эта функция отличается от других тем, что она изменяет исходную строку Str, обрезает ее. Другие функции оставляли эту строку без изменений. Итак, наш новый код:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      s1: String;
    begin
      s1:= 'Привет';
      UTF8Delete(s1, 3, 2); //обрезаем строку
      ShowMessage(s1);
    end;
        

    Функцией UTF8Delete(s1, 3, 2) мы ампутировали строку s1, вырезали из нее, начиная с третьего символа, подстроку размером 2 символа. В результате у нас осталась строка "Прет". Как и с предыдущими функциями, применение с кириллицей не UTF8-варианта исказит результат.

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

    Иногда требуется сравнить две строки, или найти какую-то подстроку. Но не всегда известно, в каком регистре пользователь ввел текст. К примеру, нам нужно узнать, ввел ли пользователь слово "Москва", или что-то другое. Пользователь знает, что он должен ввести название нашей столицы, однако он может полениться нажать <Shift>, и в результате введет "москва". Или нажмет <Caps Lock> и введет "МОСКВА". А поскольку слово он написал без ошибок, то уверен, что все сделал правильно. Но мы-то ожидаем не просто слово, а слово со строго определенным описанием! К сожалению, пользователи далеко не всегда вводят то, что нужно, и программистам приходится идти на всевозможные хитрости, чтобы добиваться нужного результата. Например, мы можем заранее преобразовать введенное пользователем слово в верхний регистр (то есть, сделать все буквы заглавными), и сравнить его со словом "МОСКВА". И какие бы буквы пользователь первоначально не вводил, результат все равно будет верным.

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

    UpperCase(Str) - Преобразует ANSI-строку Str в верхний регистр
    UTF8UpperCase(Str) - Преобразует UTF8-строку Str в верхний регистр
    LowerCase(Str) - Преобразует ANSI-строку Str в нижний регистр
    UTF8LowerCase(Str) - Преобразует UTF8-строку Str в нижний регистр

    Изменим код обработчика:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      s1: String;
    begin
      s1:= 'Москва';
      ShowMessage(UTF8UpperCase(s1));
      ShowMessage(UTF8LowerCase(s1));
    end;
        

    Сохраните проект и запустите его на выполнение. Мы получим два сообщения: заглавными и строчными буквами.

    Функции-сообщения

    Нам то и дело требуется выводить пользователю различные сообщения. И в этой лекции, и в предыдущих лекциях, мы уже неоднократно пользовались одной такой функцией - ShowMessage(). Её синтаксис очень простой:

    ShowMessage('Текст сообщения');
        

    В результате будет выведено окно с сообщением, которое не даст пользователю продолжать работу, пока он не нажмет кнопку "ОК":

    (рис 6.2) Сообщение ShowMessage()

    Application.MessageBox()

    Еще один вариант сообщения - функция Application.MessageBox(). Данная Windows API-функция позволяет вывести сообщение с разными настройками. Синтаксис функции следующий:

    Application.MessageBox(Text: PChar; Caption: PChar; Flags: LongInt): Integer;
            

    В качестве аргументов мы должны указать текст сообщения Text, заголовок окна с сообщением Caption и флаги - значок сообщения и используемые кнопки. И Text, и Caption имеют тип PChar. Флаги имеют целочисленный тип, однако нам нужно запомнить только символьные обозначения этих флагов:

    Флаги функции Application.MessageBox()
    Значки сообщения
    MB_ICONERROR Белый крестик в красном круге. Такой значок обычно используют в сообщениях об ошибке.
    MB_ICONHAND
    MB_ICONSTOP

    MB_ICONQUESTION

    Синий знак вопроса в белой выноске. Таким способом помечают вопрос, обращенный к пользователю.
    MB_ICONWARNING Черный восклицательный знак в желтом треугольнике. Таким знаком привлекают внимание пользователя к вероятной опасности, которая может последовать в результате действий пользователя.
    MB_ICONEXCLAMATION
    MB_ICONINFORMATION Синяя буква "i" в белой выноске. Таким способом помечают какую-то информацию для пользователя.
    MB_ICONASTERISK
    Кнопки сообщения
    MB_OK Кнопка "OK" в середине окна.
    MB_OKCANCEL Кнопки "OK" и "Cancel".
    MB_ABORTRETRYIGNORE Кнопки "Abort", "Retry" и "Ignore".
    MB_YESNOCANCEL Кнопки "Yes", "No" и "Cancel".
    MB_YESNO Кнопки "Yes" и "No".
    MB_RETRYCANCEL Кнопки "Retry" и "Cancel".

    Примечание: Чтобы пользоваться функцией Application.MessageBox(), нужно в разделе uses подключить модуль LCLType.

    Как видно из таблицы, некоторые значки сообщений совпадают. Указывать нужно какое-то одно из них. Переделаем код обработчика кнопки:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Application.MessageBox('Сообщение', 'Заголовок',
                              MB_ICONINFORMATION + MB_ABORTRETRYIGNORE);
    end;
            

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

    (рис 6.3) Сообщение Application.MessageBox()

    Вы заметили, что в качестве флага используется сумма значка и кнопок? И то, и другое, на самом деле, целое число. Но нам удобней запомнить эти значения в символьном варианте.

    А как мы узнаем, какую кнопку нажал пользователь? Эта функция возвращает значение - кнопку, нажатую пользователем, которая может быть:

  • IDOK
  • IDCANCEL
  • IDABORT
  • IDRETRY
  • IDIGNORE
  • IDYES
  • IDNO
  • IDCLOSE
  • IDHELP
  • То есть, если пользователь нажал кнопку "Abort", функция вернет значение IDABORT. А раз так, мы можем делать проверку на нажатую кнопку. Снова изменим код обработчика:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if Application.MessageBox('Сообщение', 'Заголовок', MB_ICONQUESTION +
         MB_YESNOCANCEL) = IDYES then ShowMessage('Вы нажали кнопку Yes');
    end;
            

    Логическую конструкцию if мы будем изучать в следующей лекции, здесь лишь заметим, что сообщение ShowMessage() будет выведено только в том случае, если пользователь нажал кнопку "Yes". Во всех остальных случаях это сообщение не выйдет.

    MessageDlg()

    Похожим образом действует Windows API-функция MessageDlg(), которая описана в модуле Dialogs. Этот модуль включается в раздел uses автоматически, поэтому нам не нужно даже что-то туда добавлять. Синтаксис этой функции несколько отличается от предыдущей:

    MessageDlg(Caption, Text, MessageType, MessageButton, HelpKeyword): Integer;
            

    Здесь Caption и Text соответственно, текст заголовка и самого сообщения, тип PChar. Далее идет тип сообщения MessageType, - значок сообщения, который может быть:

    mtWarning - Восклицательный знак, подобен MB_ICONWARNING функции Application.MessageBox()
    mtError - крестик
    mtInformation - буква "i"
    mtConfirmation - вопросительный знак
    mtCustom - пользовательское окно без значка.

    Далее следует тип кнопок MessageButton, который может быть:

    mbYes
    mbNo
    mbOK
    mbCancel
    mbAbort
    mbRetry
    mbIgnore
    mbAll
    mbNoToAll
    mbYesToAll
    mbHelp
    mbClose

    Названия кнопок говорят сами за себя, комментарии тут излишни. Кнопки указывают в квадратных скобках, отделяя друг от друга запятыми, например: [mbYes, mbNo, mbIgnore].

    Последний параметр HelpKeyword определяет экран контекстной справки, которая будет появляться, если пользователь нажмет <F1>. Обычно в этом параметре указывают значение 0 - нет справки.

    Функция MessageDlg() возвращает значение - нажатую кнопку, которая соответствует типу кнопок, указанному выше. Возвращаемое значение вместо "mb" начинается на "mr", то есть, если пользователь нажал кнопку "Yes" (тип mbYes), то будет возвращено значение mrYes.

    Снова изменим код:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if MessageDlg('Подтверждение', 'Вы действительно хотите закрыть программу?',
                 mtConfirmation, [mbYes, mbNo, mbIgnore], 0) = mrYes then Close;
    end;
            

    В данном случае пользователю выводится запрос на подтверждение закрытия программы, и если он нажимает кнопку "Yes", программа закрывается (выполняется оператор Close). Так как функции MessageDlg() и Application.MessageBox() похожи, выбирайте любую, на свой вкус.

    Функция-запрос

    Иногда требуется получить от пользователя какие-то данные (вспомните программу Hello из второй лекции). В этом случае можно использовать компонент TEdit, но можно поступить проще - воспользоваться функцией InputQuery().

    Функция InputQuery() выводит окно запроса. Синтаксис функции такой:

    InputQuery(Caption, Message, StrVar);
        

    Здесь, Caption и Message - соответственно, текст заголовка и текст сообщения внутри окна. StrVar - переменная строкового типа, которая должна быть объявлена заранее. Если в этой переменной есть текст, он выводится в строке редактирования как текст по умолчанию. Если переменная пуста, то пуста будет и строка. Если пользователь что-то введет в строку и нажмет кнопку "ОК", этот текст запишется в переменную StrVar, а функция вернет значение True (Истина). В противном случае функция вернет значение False (Ложь). Переделаем код обработчика:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      YourName: String;
    begin
      YourName:= 'Неизвестный';
      if InputQuery('Кто вы?', 'Укажите ваше имя', YourName) then
         ShowMessage('Привет, ' + YourName + '!');
    end;
        

    Напомню, что с логической конструкцией if мы познакомимся в следующей лекции, а пока разберем код. Вначале мы присваиваем строковой переменной YourName текст "Неизвестный". Затем мы вызываем функцию InputQuery(). Мы указываем заголовок окна "Кто вы?", текст сообщения "Укажите ваше имя" и текстовую переменную YourName. Текст, который мы ранее поместили в эту переменную, будет выходить в строке редактирования:

    (рис 6.4) Результат работы функции InputQuery()

    Если пользователь введет какой-то другой текст, он попадет в переменную YourName, функция вернет True и в результате будет выведено сообщение с приветствием

         ShowMessage('Привет, ' + YourName + '!');
        

    Функция InputQuery() часто бывает полезна, так что запомните её получше.

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