Стандартная библиотека: Строки
В предыдущих главах мы видели примеры исходного кода с использованием
типа String
, который является строковым типом фиксированной
длины - по сути, это массив символов. Во многих случаях этого типа данных
достаточно для работы с текстовой информацией. Однако бывают ситуации, когда
требуется более сложная обработка текста. Ада предлагает
альтернативные подходы для этих случаев:
Ограниченные строки: аналогично строкам фиксированной длины, ограниченные строки имеют максимальную длину, которая устанавливается при их создании. Однако ограниченные строки не являются массивами символов. В любой момент они могут содержать строку различной длины - при условии, что эта длина меньше или равна максимальной длине.
Неограниченные строки: подобно ограниченным строкам, неограниченные строки могут содержать строки различной длины. Однако, помимо этого, у них нет максимальной длины. В этом смысле они очень гибкие.
В следующих разделах представлен обзор различных типов строк и общих операций для типов строк.
Операции со строками
Операции со стандартными строками (фиксированной длины) доступны в
пакете Ada.Strings.Fixed
. Как упоминалось ранее, стандартные строки
представляют собой массивы элементов типа Character
с фиксированной длиной. Вот почему этот дочерний пакет называется
фиксированным (Fixed
).
Одна из самых простых операций - это подсчет количества подстрок,
доступных в строке (Count
), и поиск их соответствующих
индексов (Index
). Давайте посмотрим на пример:
Мы инициализируем строку S
умножением. Запись
"Hello" & 3 * " World"
создает строку Hello World World World
.
Затем мы вызываем функцию Count
, чтобы получить количество экземпляров
слова World
в S
.Затем мы вызываем функцию Index
в
цикле, чтобы найти индекс каждого экземпляра слова World
в S
.
В этом примере искались вхождения определенной подстроки. В следующем
примере мы извлекаем все слова в строке. Мы делаем это с помощью
Find_Token
, определив пробелы в качестве разделителей. Например:
Мы передаем множество символов, которые будут использоваться в качестве
разделителей для процедуры Find_Token
. Это множество является значением
типа Character_Set
из пакета Ada.Strings.Maps
. Мы вызываем
функцию To_Set
(из того же пакета), чтобы инициализировать множество
Whitespace
, а затем вызываем Find_Token
, чтобы перебрать
все возможные индексы и найти начальный индекс каждого слова. Мы
передаем Outside
в параметр Test
процедуры Find_Token
,
чтобы указать, что мы ищем индексы, которые находятся за пределами множества
Whitespace
, то есть фактические слова. First
и Last
параметры Find_Token
являются выходными параметрами, которые указывают
допустимый диапазон подстроки. Мы используем эту информацию для
отображения строки (S (F .. L)
).
Операции, которые мы рассмотрели до сих пор, читают строки, но не изменяют их. Далее мы обсудим операции, которые изменяют содержимое строк:
Operation |
Description |
---|---|
Insert |
Вставка подстроки в строку |
Overwrite |
Замена подстроки в строке |
Delete |
Удаление подстроки |
Trim |
Удаление пробелов из строки |
Все эти операции доступны как в виде функций, так и в виде процедур.
Функции создают новую строку, но процедуры выполняют операции по
месту. Процедура вызовет исключение, если ограничения строки будут
нарушены. Например, если у нас есть строка S
, содержащая 10 символов,
вставка в нее строки с двумя символами (например, "!!"
) дает строку,
содержащую 12 символов. Поскольку она имеет фиксированную длину, мы не
можем увеличить его размер. Одно из возможных решений в этом случае -
указать, что при вставке подстроки следует применять усечение. Это
сохраняет длину S
. Давайте посмотрим на пример, в котором используются
как функции, так и версии процедур Insert
, Overwrite
и
Delete
:
В этом примере мы ищем индекс подстроки World
и выполняем операции с
этой подстрокой внутри внешней строки. Процедура Display_Adapted_String
использует обе версии операций. Для процедурной версии Insert
и
Overwrite
мы применяем усечение к правой стороне строки
(Right
). Для процедуры Delete
мы указываем диапазон подстроки,
которая заменяется пробелами. Для функциональной версии Delete
мы
также вызываем Trim
. Эта функция которая обрезает конечные пробелы.
Ограничение строк фиксированной длины
Использование строк фиксированной длины обычно достаточно хорошо для строк, которые инициализируются при их объявлении. Однако, как видно из предыдущего раздела, процедурные операции со строками вызывают трудности при работе со строками фиксированной длины, поскольку строки фиксированной длины представляют собой массивы символов. В следующем примере показано, насколько громоздкой может быть инициализация строк фиксированной длины, если она не выполняется в объявлении:
В этом случае мы не можем просто написать S := "Hello"
, потому что
результирующий массив символов для константы Hello
имеет длину,
отличную от длины строки S
.Следовательно, нам необходимо включить
конечные пробелы, чтобы соответствовать длине S
. Как показано в
примере, мы могли бы использовать точный диапазон для инициализации
(S (1 .. 5)
) или использовать явный массив отдельных символов.
Когда строки инициализируются или обрабатываются во время выполнения, обычно лучше использовать ограниченные или неограниченные строки. Важной особенностью этих типов является то, что они не являются массивами, поэтому описанные выше трудности не применяются. Начнем с ограниченных строк.
Ограниченные строки
Ограниченные строки определены в пакете
Ada.Strings.Bounded.Generic_Bounded_Length
. Поскольку это общий пакет,
вам необходимо создать его экземпляр и установить максимальную длину
ограниченной строки. Затем вы можете объявить ограниченные строки типа
Bounded_String
.
Строки как ограниченной, так и фиксированной длины имеют максимальную длину, которую они могут вместить. Однако ограниченные строки не являются массивами, поэтому их инициализация во время выполнения намного проще. Например:
Используя ограниченные строки, мы можем легко назначить S1
и S2
несколько раз во время выполнения. Мы используем функции
To_Bounded_String
и To_String
для преобразования
в соответствующем направлении между строками фиксированной длины и
ограниченными строками. Вызов To_Bounded_String
возбуждает исключение,
если длина входной строки больше максимальной длинны ограниченной строки.
Чтобы этого избежать, мы можем использовать параметр усечения (Right
в нашем примере).
Ограниченные строки не являются массивами, поэтому нельзя использовать
атрибут 'Length
, как это было для строк фиксированной длины. Вместо
этого вызывается функция Length
, которая возвращает длину
ограниченной строки. Константа Max_Length
представляет максимальную
длину ограниченной строки, заданную при настройке экземпляра пакета.
После инициализации ограниченной строки мы можем с ней работать.
Например, мы можем добавить строку в ограниченную строку с помощью
Append
или выполнить конкатенацию ограниченных строк с помощью оператора
&
. Вот так:
Мы можем инициализировать ограниченную строку пустой строкой,
используя константу Null_Bounded_String
. Кроме того, можно
использовать процедуру Append
и указать режим усечения,
как в случае с функцией To_Bounded_String
.
Неограниченные строки
Неограниченные строки определяются в пакете Ada.Strings.Unbounded
.
Это не настраиваемый пакет, поэтому нам не нужно создавать его экземпляр
перед использованием Unbounded_String
типа. Как можно вспомнить из
предыдущего раздела, для ограниченных строк требуется настройка пакета.
Неограниченные строки похожи на ограниченные строки. Главное отличие состоит в том, что они могут содержать строки любого размера и подстраиваться в соответствии с входной строкой: если мы назначим, например, 10-символьную строку неограниченной строке, а позже назначим 50-символьную строку, внутренние операции в контейнере обеспечат выделение памяти для хранения новой строки. В большинстве случаев разработчикам не нужно беспокоиться об этих операциях. Кроме того, усечение не требуется.
Инициализация неограниченных строк очень похожа на ограниченные строки. Рассмотрим пример:
Как и ограниченные строки, мы можем назначать S1
и S2
несколько
раз во время выполнения и использовать функции To_Unbounded_String
и
To_String
для преобразования строк
фиксированной длины в неограниченные строками и обратно. В этом случае усечение
не нужно.
Как и для ограниченных строк, можно использовать процедуру Append
и
оператор &
для неограниченных строк. Например: