4.2.2. Булевские типы
Булевские (boolean) типы являются одними из простейших. Диапазон их значений содержит всего два элемента, один для обозначения истинности, другой – ложности. Впервые эти типы появились в языке ALGOL 60 и с 1960 года были включены в большинство универсальных языков программирования. Исключением является язык C, в котором в качестве условных выражений могут использоваться числовые выражения. В таких выражениях все операнды с ненулевыми значениями считаются истинными, тогда как нуль считается ложным значением. Несмотря на то, что в языке C++ булевский тип предусмотрен, в этом языке также можно использовать числовые выражения вместо булевских.
Булевские типы часто применяются для представления переключателей или признаков. Хотя для этих целей могут использоваться и другие типы (например, целый), булевские типы повышают читабельность программы.
Булевские значения могут представляться единственным битом, но, поскольку на многих машинах к отдельному биту памяти обращение неэффективно, эти значения часто содержатся в минимальной ячейке памяти, имеющей эффективно доступный адрес, которой обычно является байт.
4.2.3. Символьные типы
Символьные данные запоминаются в компьютерах с помощью цифрового кодирования. Наиболее распространенной системой кодировки является система ASCII (American Standard Code for Information Interchange – Американский стандартный код обмена информацией), в которой для кодировки 128 различных символов используется диапазон значений 0–127. В качестве средства обработки кодов отдельных символов многие языки программирования предусматривают для них отдельный основной тип.
Вследствие глобализации коммерции и необходимости связи между компьютерами во всем мире набор символов ASCII стал недостаточным. Не так давно был разработан альтернативный 16-битовый набор символов, получивший название Unicode. В этом наборе содержатся символы большинства естественных языков мира. Например, в нем есть символы кириллицы и тайские цифры. Первым широко распространенным языком, использующим набор символов Unicode, явился язык Java. Впоследствии этот набор нашел применение и в других популярных языках, например, C#.
4.3. Символьные строки
Символьные строки представляют собой последовательности символов. Константные строки символов сопровождают вывод результатов. Также ввод и вывод всех типов данных часто производится посредством строк. Строки символов играют существенную роль во всех программах, работающих с символьными данными. Два важнейших вопроса разработки, связанных с символьными строками, таковы.
Должны ли строки быть разновидностью массива, состоящего из символов, или элементарным типом (без индексации, характерной для массивов)?
Должны ли строки иметь статическую или динамическую длину?
4.3.1. Строки и действия над ними
Если в языке строка не определена как элементарный тип, то строковые данные обычно хранятся в массивах отдельных символов, и ссылаться на них можно, лишь как на элементы массивов. Такой подход принят в языках Pascal, С, C++ и Ada. В классическом языке Pascal, где строки не являются основным типом, значения могут присваиваться массивам char, имеющим атрибут packed, и такие массивы могут сравниваться между собой с помощью операторов отношений. В более поздних диалектах Pascal (Delphi) строка уже является стандартным типом.
В языке Ada тип STRING является встроенным и определяет одномерные массивы элементов, принадлежащих к типу CHARACTER. Для типов STRING предусмотрены операции обращения к подстрокам, конкатенация, операторы отношений и присваивания. Обращение к подстрокам позволяет интерпретировать любую подстроку данной строки как величину, на которую можно ссылаться, или переменную, которая может входить в оператор присваивания. Обращение к подстроке обозначается целочисленным диапазоном, взятым в круглые скобки и указывающим расположение требуемых символов. Например, команда
NAME1(2:4)
задает подстроку, состоящую из второго, третьего и четвертого символа строки, являющейся значением переменной NAME1.
Конкатенация строк символов в языке Ada является операцией, обозначаемой символом &. Следующий оператор выполняет присоединение переменной NAME2 к правому концу строки, являющейся значением переменной NAME1:
NAME1 := NAME1 & NAME2;
В языках C и C++ для хранения строк используются массивы char, а набор операций со строками предусмотрен в стандартной библиотеке с заголовочным файлом string.h. В большинстве операций со строками и в большинстве библиотечных функций подразумевается, что строки символов завершаются специальным символом – нулевым байтом. Это соглашение является альтернативой хранению длины строковых переменных. Библиотечные функции выполняют свои операции, пока не дойдут в обрабатываемой строке до нулевого байта. Библиотечные функции, создающие строки, сами вносят в них нулевой байт. Литералы символьных строк, создаваемые компилятором, также содержат нулевой байт. Рассмотрим следующее объявление:
char *str = "apples";
В этом примере str – указатель типа char, адресующий строку символов apples с нулевым байтом в конце. Инициализация указателя str разрешена, поскольку литералы символьных строк представляются указателями типа char, а не собственно строкой.
В языках FORTRAN 77, FORTRAN 90 и BASIC строки интерпретируются как основные типы, и для них предусмотрены операции присваивания, конкатенации, ссылки на подстроки, а также операторы отношения.
В языке Java строки поддерживаются классом string как встроенные типы, значения которых являются константными строками, и классом StringBuffer, значения которого могут изменяться, и более всего похожи на массивы отдельных символов. Использование подстрок разрешено для переменных класса StringBuffer. Язык C# поддерживает обладающий широкой функциональностью встроенный тип string.
Операции присваивания и сравнения символьных строк усложнены возможностью использования операндов различных длин. Что произойдет, например, при присвоении более длинной строки более короткой строке или наоборот? Обычно в таких ситуациях принимаются простые и целесообразные решения, хотя пользователи часто сталкиваются с проблемами при их запоминании.
Еще одной базовой операцией со строками символов является сопоставление с образцом. Часто она обеспечивается библиотечной функцией, а не операцией языка. Одним из исключений является язык SNOBOL4, содержащий встроенную операцию сопоставления с образцом. Этот язык предоставляет максимально полные возможности для работы со строками. Образцами строк в языке SNOBOL4 являются выражения, которые могут присваиваться переменным. Рассмотрим следующий фрагмент:
LETTER = 'abcdefghijklmnopqrstuvwxyz'
WORDPAT = BREAK(LETTER) SPAN(LETTER).WORD
LETTER – это переменная, значением которой является строка из всех строчных букв латинского алфавита. WORDPAT – образец, следующим образом описывающий слова: вначале пропускаются все символы, пока не будет найдена буква, затем буквы перебираются, пока не будет найден символ, не являющийся буквой. Образец также содержит оператор «.». Он указывает, что строка, совпавшая с образцом, присваивается переменной WORD. Указанный образец может использоваться, например, в операторе
TEXT WORDPAT
Этот оператор пытается найти строку подряд расположенных букв в значении переменной TEXT.
Вторым важным языком, содержащим встроенные операции сопоставления с образцом, является язык Perl. В этом случае выражения сопоставления с образцом напоминают математические регулярные выражения. Они произошли от раннего строчного редактора ed операционной системы UNIX и стали частью языков оболочек системы UNIX. В итоге самой сложной формой этих языков стал язык Perl. Объяснение этих выражений довольно громоздко и занимает отдельную главу в книге по языку Perl. Уже существуют книги, посвященные выражениям сопоставления с образцом. Мы рассмотрим лишь два простых примера. Пусть имеется следующее выражение-образец:
/[A-Za-z][A-Za-z\d]+/
Он соответствует типичной форме имен в языках программирования. В квадратных скобках заключены классы символов. Первый класс задает все буквы; второй – все буквы и цифры (цифра задается сокращением \d). Если оставить только второй класс, то не удастся запретить имена, начинающиеся с цифр. Следующий за второй категорией знак «+» устанавливает, что в имени должно содержаться не менее одного символа, входящего в данную категорию. Таким образом, рассматриваемый эталон соответствует строке, начинающейся с буквы, за которой следует не менее одной буквы или цифры. Рассмотрим следующее выражение-образец:
/\d+\ .?\d* | \ .\d+/
Этот образец соответствует числовым константам. Символы \ . задают точку в десятичной записи числа. Вопросительный знак определяет количество (0 или 1) появлений того, что следует за ним. Вертикальная черта ( | ) разделяет два альтернативных варианта всего образца. Первый вариант соответствует строкам с несколькими цифрами, за которыми, возможно, следует десятичная точка и цифры; вторая альтернатива соответствует строкам, начинающимся с десятичной точки, за которой следует не менее одной цифры.
