Помимо чисел, к скалярным значениям в Athanor относятся строки. Строка – это последовательность символов (возможно, пустая). Диапазон значений символов определятся типом строки. Как и для числовых операций, многие строковые могут быть заданы как в операторной, так и в функциональной форме. С точки зрения выполнения, результат будет одинаков. Большая часть функторов, работающих со строками, имеют имена, начинающиеся с префикса s_. В своей операторной форме, они почти всегда имеют суффикс "$", позволяющий отличать их от числовых операций.
Простейшие строковые значения – литеральные. В качестве ограничителей строкового литерала допустимы как одинарные, так и двойные кавычки: например, '46gh89as' или "Hello, world!". Внутри допустимы некоторые стандартные последовательности с символом \: например, '\n' – перевод строки, '\r' – возврат каретки, '\t' – табуляция, '\a' – звуковой сигнал и пр. Сам символ \ также экранирует как кавычку любого типа, так и сам себя.
Рассмотрим теперь операции над строками. Начнем с простейших:
|
#$ S
|
s_len (S)
|
длина строки S (= количество символов в ней)
|
|
~$ S
|
s_rev (S)
|
реверсия строки S
(S с последнего символа по первый)
|
|
s_type (S)
|
тип строки S
|
Понятие о типе строки требует отдельных пояснений. Сейчас в языке строки могут быть трёх типов (в зависимости от разрядности своих элементов): тип 0 – восьмибитовые; тип 1 – 16-ти битовые; тип 2 – 32-х битовые. Строки типа 0 могут содержать только символы из базового набора символов ASCII, типа 1 – полный набор Unicode-16, типа 2 - полный набор Unicode без ограничений (и даже более того). Кроме того, строки могут использоваться не только по прямому назначению (т.е. как последовательности символов), но и как контейнеры, для хранения и обработки бинарных данных, таких, как графика или аудио. Большая часть рассматриваемых здесь операций корректно работает со строками любого типа (а когда тип строки нужен явно, или на что-то влияет, мы непременно будем отмечать это особо).
|
S +$ T
|
s_cat (S,T)
|
конкатенация (сцепление) строк S и T
|
|
S *$ N
|
s_rep (S,N)
|
репликация строки S (N раз)
|
Последняя операция возвращает строку S, повторённую (реплицированную) N раз подряд. Если значение N меньше или равно нулю – возвращается пустая строка.
Строковые значения в Athanor являются упорядоченными лексикографически (то есть, в соответствии со словарной логикой). Как и числовые значения, строки тоже можно сравнивать специальными операциями-предикатами:
|
S <$ T
|
s_lt (S,T)
|
S (словарно) меньше T?
|
|
S <=$ T
|
s_le (S,T)
|
S (словарно) меньше или равно T?
|
|
S >$ T
|
s_gt (S,T)
|
S (словарно) больше T?
|
|
S >=$ T
|
s_ge (S,T)
|
S (словарно) больше или равно T?
|
|
S ==$ T
|
s_eq (S,T)
|
S равно T?
|
|
S <>$ T
|
s_ne (S,T)
|
S не равно T?
|
Как и все предикаты, эти операции возвращают 1, если условие истинно, и 0, если оно ложно.
Для строк определена операция-компаратор (аналогичная таковой для чисел), определяющая их относительный порядок:
|
S <?>$ T
|
s_cmp (S,T)
|
порядок строк S и T в словаре
|
Здесь результатом является: -1 (если S <$ T), +1 (если S >$ T) или 0 (если операнды равны).
Наконец, для строк доступны операции словарного максимума и минимума:
|
S ?<$ T
|
s_min (S,T)
|
меньшая (словарно) из строк S и T
|
|
S ?>$ T
|
s_max (S,T)
|
большая (словарно) из строк S и T
|
На все операции строкового сравнения, а также на максимум и минимум – оказывает сильное влияние активный режим сравнения символов. Режимы могут быть разные (в том числе, и специфичные для конкретной локали, а также отключающие чувствительность к регистру символов, диакритике и пр.) – но это уже отдельная, довольно специфичная тема для рассмотрения. А пока что, ограничимся тем, что когда какие-либо особые режимы сравнения символов не задействованы явно – они всегда будут сравниваться просто по порядку своих кодов (несколько наивный подход для Unicode).
Для конкатенации нескольких строк подряд (с разделителями) предусмотрена специальная операция:
Эта операция возвращает результат последовательного сцепления своих операндов (с S1 по Sn), вставляя между ними строку Del в качестве разделителя. Другими словами, результат выполнения равносилен S1 +$ Del +$ S2 +$ Del +$ ... +$ Sn (но при этом s_join выполняется заметно эффективнее, чем длинная последовательность конкатенаций). Заметим, что это первый рассмотренный здесь функтор, имеющий нефиксированную арность, то есть количество аргументов. Отдельной "операторной" формы у него нет.
Обратная (в некотором роде) операция – вырезание некого фрагмента из строки – реализуется обращением к s_slice (для которого есть и операторная запись):
|
S $[From..To]
|
s_slice (From..To, S)
|
отрезок строки S (от From до To)
|
Этот функтор тоже считается бинарным, что может показаться непонятным (разве у него не три аргумента)? Однако, диапазон From..To – это один аргумент, задающий два числовых значения в виде списка. На самом деле, встроенных операций, операндами которых являются списки (и даже более сложные структуры данных) в языке немало. Но подробнее о диапазонах (как и списках вообще) несколько позже, сейчас же заметим, что его первый элемент (From) задает индекс начального символа подстроки, а второй (To) – на единицу больше, чем индекс конечного её символа. Таким образом, длина вырезанного фрагмента по определению всегда будет равна (To–From). Все символы строки индексируются с 0. (Например, выражение «Запредельный» $[2..8] – возвращает строку «предел».)
Любая из границ диапазона может быть опущена. Если опущено значение From – берётся отрезок с начала строки (т.е. From = 0); если опущено значение To – берётся отрезок до конца строки (т.е. To = s_len (S)). Могут быть даже опущены обе границы (хотя в этом случае операция не имеет особого смысла, т.к. просто возвращает операнд S без изменений). Наконец, значения границ могут даже выходить за пределы дозволенного! Если значение индекса From меньше 0, и/или значение индекса To больше s_len (S) – результат операции дополняется пробелами в начале и/или в конце до требуемой длины (что иногда бывает весьма удобным). Если диапазон некорректен (From >= To), возвращается пустая строка.
Из строки можно извлекать символы и по отдельности. Результат s_ord (S,n) – это код символа в позиции n строки S. Осторожно: возвращается именно целое число (код символа ASCII/Unicode), а не строка! Второй операнд может быть опущен: s_ord (S) эквивалентно s_ord (S,0) (т.е. возвращает код первого символа строки).
Обратная (в некоторой степени) операция – s_chars: она возвращает строку, состоящую из символов, явно заданных своими кодами. Результат s_chars (Type, Code1, Code2, ... CodeN) – это строка (типа Type), состоящая из N символов с кодами Code1, Code2, ... CodeN. Заметим, это одна из немногих операций, где тип строки-результата (0, 1 или 2) требуется задать явно. Например, s_chars (0, 48, 49, 50, 51) – возвращает строку "0123" (типа 0, т.е. восьмибитовую).
Наконец, в строке можно производить поиск:
|
S >>$ T
|
s_findfirst (S,T)
|
найти первое вхождение T в S
|
|
S <<$ T
|
s_findlast (S,T)
|
найти последнее вхождение T в S
|
Обе операции возвращают позицию (начиная с 0) подстроки T в S, если она найдена (или же -1, если её там найти не удалось). Например: «водоворот» >>$ «во» – возвращает 0; «водоворот» <<$ «во» – возвращает 4.
В языке определено намного больше функторов, работающих со строками – но пока что, мы ограничимся перечисленными.
В заключение, рассмотрим совместное использование операций для числовых и строковых типов. В Athanor происходит неявное приведение (коерсия) не только между числовыми типами, но и между числами и строками. Например, если функтор ожидает строковый операнд, а ему передается число – оно автоматически преобразуется в свое стандартное строковое представление. Справедливо и обратное: если требуется числовое значение, но передана была строка – функтор автоматически пытается распознать её, как число (игнорируя начальные пробелы). (Если не удастся, строка воспринимается как 0 и ошибки не обрабатываются; возможный «мусор» в конце строки также молча игнорируется.) Заметим, что в Athanor (как и в Perl) для встроенных функторов всегда известно, какой именно тип операнда ожидается. То есть (в отличие от, скажем, Python или JavaScript) в языке нет перегруженных операций (когда, например, бинарный «+» может использоваться и для сложения, и для конкатенации). В Athanor это гарантированно разные операции: операция «+» (add) всегда выполняет арифметическое сложение («22» + «33» возвращает число 55), а операция «+$» (s_cat) всегда выполняет конкатенацию строк (22 +$ 33 возвращает строку «2233»). Аналогично, будет грубой ошибкой использовать числовую операцию сравнения там, где нужно сравнивать строки, и наоборот.
В нетривиальных случаях, могут быть полезны и явные приведения:
А также есть и обратная операция:
Наконец, имеется и функтор-предикат для проверки своего операнда на принадлежность к строковому типу: