Прежде всего, для объединения (конкатенации) строк и/или символьных значений предназначены cat-функция и ||-оператор конкатенации, имеющие следующие довольно простые форматы кодирования, а именно:
cat(S1, S2, ..., Sn) и S1||S2|| ... ||Sn
возвращающие результат конкатенации Sk-строк/символов. В случае использования бинарного ||-оператора в качестве первого операнда должно быть символьное либо строчное выражение. Тип возвращаемого результата в обоих случаях определяется типом первого соответственно фактического аргумента и операнда, например:
> map(whattype, map2(cat, "TRG", ["IAN", RANS])); ⇒ [string, string]
> map(whattype, map2(cat, TRG, ["IAN", RANS])); ⇒ [symbol, symbol]
> whattype("TRG"||RANS), whattype(TRG||"RANS"); ⇒ string, symbol
При этом, следует отметить, что в качестве первого операнда ||-оператора могут выступать и более общего вида выражения, однако как для cat-функции, так и для оператора конкатенации имеет место ряд особенностей (детально представленных в [12-14,39]), позволяющих рассматривать их, прежде всего, именно как средства работы со строчными данными и структурами. По substring-функции, имеющей простой формат кодирования: substring({"<Строка>"|`<Символ>`}{, m|, m..n})
возвращается соответственно {строка|символ}, находящиеся на m-й позиции заданного первым фактическим аргументом значения {string|symbol}-типа или начинающиеся с m-й и заканчивающиеся n-й позицией. В случае отрицательных значений позиций отсчет производится, начиная с правой границы исходных {строки|символа}. Тогда как вызов length(<Выражение>)-функции возвращает длину результата вычисления выражения и в случае его типа {string| {symbol|name}} – длину {строки|символа}. Для целых числовых значений возвращается число цифр, исключая знак; тогда как для других Maple-выражений по length-функции возвращается результат, определяемый как сумма длин каждого операнда выражения, вычисляемых рекурсивно, и числа слов, используемых для представления исходного выражения. Данный результат определяет своего рода числовую меру сложности выражения. Следующий простой фрагмент иллюстрирует сказанное:
> H:= `Russian Academy of Natural Sciences`: M:= "Tallinn Research Group":
> map(length, [H, M, 42.64, -59, cat(H, M), ``||H||M, sin(x)+y^2]); ⇒ [35,22,8,2,57,57,21]
> cat(substring(H, 9 .. 15),`, `, substring(M, 9 .. length(M))); ⇒ Academy, Research Group
> cat(sin(x), TRU), cat(convert(sin(x), 'string'), TRU); ⇒ || (sin(x)) || TRU, "sin(x)TRU"
Таким образом, если относительно функций cat и length допускаются значения фактических аргументов типов {string, symbol, name} с учетом того, что тип возвращаемого catфункцией результата определяется типом ее первого аргумента, то уже в общем случае ||-оператора конкатенации требуется специальный формат его кодирования. Тогда как последний пример фрагмента хорошо иллюстрирует тот факт, что в общем случае произвольное Maple-выражение, выступающее в качестве аргумента (операнда) cat-функции (||-оператора), предварительно следует конвертировать в строку либо символ.
По функции {searchtext|SearchText}, имеющей следующий формат кодирования:
{searchtext|SearchText}(`<Контекст>`, {"<Строка>"|`<Символ>`}{, m..n}) производится регистро-{независимая|зависимая} идентификация факта вхождения заданного контекста в заданные {строку|символ}. Если закодирован и третий аргумент (позиции), то поиск осуществляется относительно указанного местоположения контекста в {строке|символе}. Сказанное о втором аргументе substring-функции полностью сохраняет силу и для третьего аргумента {searchtext|SearchText}-функции. Обе функции поиска возвращают позицию первого вхождения контекста в строку; нулевое значение говорит об отсутствии в строке искомого контекста. При этом, следует иметь в виду, что возвращаемый по searchtext(Контекст, S, n..p)-вызову номер позиции (m) первого вхождения искомого контекста в S-строку в диапазоне [n..p] отсчитывается не от начала строки, а от n-позиции, как базовой; т.е. относительно начала строки номер позиции определяется как (n+m), что следует учитывать при программировании с использованием данного средства Maple-языка.
При этом, на основе SearchText-функции Maple-язык предоставляет и недокументированную процедуру search(S, s {, 't'}), которая тестирует факт вхождения s-подстроки в S-строку (в качестве s и S могут выступать символы и/или строки), возвращая соответственно true или false. Если при вызове процедуры быд определен и третий необязательный t-аргумент, то через него возвращается позиция первого вхождения s в S; при отсутствии такого вхождения t-аргумент возвращается невычисленным. Следующий простой пример хорошо иллюстрирует вышесказанное:
> searchtext(`_`, Academy_Nooshpere), [search(Academy_Nooshpere, `_`, 'p'), p];
8, [true, 8]
> SearchText(n, Academy_Nooshpere), SearchText(N, Academy_Nooshpere); ⇒ 0, 9
По конструкции вида {\n} можно определять режим переноса строчного выражения на новую строку, кодируя его в нужных местах длинных строчных или символьных выражений, например:
> `Address: \nRaadiku 13 - 75\nTallinn 13817\nEstonia\nwww.aladjev.newmail.ru`;
Address:
Raadiku 13 – 75
Tallinn 13817 Estonia
www.aladjev.newmail.ru
Для обеспечения синтаксического анализа строчной структуры, заключающей в себе Maple-выражение/предложение, служит parse-функция, имеющая форматы: parse({ |"<Строка>"|"<Строка>", <Параметры>})
parse({ |`<Символ>`|`<Символ>`, <Параметры>})
Предполагается, что содержимое аргумента “Строка” определяет одно Maple-выражение либо предложение, если указан statement-параметр в качестве второго аргумента функции. Данная функция производит синтаксический анализ заданной своим первым аргументом строки, как если бы она была введена в Input-параграфе или считана из файла. Выражение/предложение, составляющее строку, анализируется на соответствие синтаксису Maple-языка и возвращается невычисленным. Если же в результате анализа обнаружена ошибка, то выводится сообщение вида: “Error, incorrect syntax in parse: <Тип ошибки> (m)”, где m-число определяет позицию строки, с которой ассоциируется обнаруженная ошибка указанного типа. Данное сообщение возможно использовать для обработки ошибочных и особых ситуаций. Даже в случая обнаружения parse-ошибки по (%)конструкции возвращается значение строки невычисленным. В случае второго формата parse-функции сохраняет силу все сказанное относительно ее первого формата, т.е. функция обрабатывает значения как string, так и symbol-типа.
Если содержимое строки – Maple-предложения не завершается {;|:}-разделителем либо символом перевода строки (СПС), то автоматически устанавливается (;)-разделитель, если не определен nonsemicolon-параметр. С другой стороны, если содержимое строки завершается {;|:}-разделителем, но не содержит СПС, то он добавляется автоматически. Наконец, по вызову функции parse() возвращается {true|false}-значение в зависимости соответственно от того, завершалось ли содержимое последней успешно обработанной parseфункцией строки (;)-разделителем либо нет. Следующий фрагмент иллюстрирует разные варианты вызова parse-функции:
> parse(`exp(Art*x) - Kr*Pi*sqrt(gamma/Catalan)`); ( ) e Art x − Kr π (Art x) > [evalf(%), parse()]; ⇒ [e − 2.493901789 Kr false, ] > parse("Z:= sqrt(Art + Kr) - a/Pi!Pi + 64*x^2;"); Error, incorrect syntax in parse: missing operator or `;` (29) > [%, parse()]; ⇒ [[e(Art x) − 2.493901789 Kr false, ], false] |
При этом, следует иметь в виду, что функция parse не всегда корректно диагностирует ошибочную ситуацию синтаксического анализа строчной конструкции, содержащей выражение/предложение Maple. Следующий фрагмент иллюстрирует вышесказанное:
> AGN:= "(x^3 + 5.9*sin(x)/(exp(10*x) - Kr*Pi*sqrt(gamma/x))": length(AGN); ⇒ 51 > parse(AGN, 'statement');
Error, incorrect syntax in parse: `;` unexpected (53)
В данном фрагменте parse-функция диагностирует отсутствие (;)-разделителя в несуществующей позиции AGN-строки {length(AGN)=51}. Более того, такая ситуация должна автоматически обрабатываться parse-функцией, как отмечено выше. Тогда как в данном случае имеет место несоответствие числа открывающих и закрывающих скобок выражения/предложения Maple, составляющего AGN-строку. Во многих случаях значение m-параметра диагностического сообщения parse-функции весьма приблизительно идентифицирует место ошибки (как правило, с точностью до операнда).
Полезные рекомендации по использованию parse-функции. Используя возможности, предоставляемые parse-функцией, можно применять их для организации весьма простого механизма динамической генерации вычисляемых Maple-выражений, включая достаточно сложные конструкции такие, как процедуры и программные модули. Пример тому дает следующая простая процедура, возвращающая в зависимости от значения ее первого фактического аргумента одну из двух активных в текущем сеансе процедур:
A := proc(x::{1, 2}, y::symbol) if x = 1 then parse("" || y || ":=() -> `+`(args):" ', statement') else parse("" || y || ":=() -> `*`(args):" ', statement') end if end proc > A(2, Sr), Sr(64, 59, 39, 44, 10, 17); ⇒ () -> `*`(args), 1101534720 > A(1, Sr), Sr(64, 59, 39, 44, 10, 17); ⇒ () -> `+`(args), 233 > A(1, Summa), Summa(64, 59, 39, 44, 10, 17); ⇒ () -> `+`(args), 233 F := (f::symbol, x::symbol, n::posint) → parse( "" || f || ":=(" || (seqstr seq(( x || k, k = 1 .. n))) || ") -> " "`+`(args)/nargs;" ' || , statement') > F(Kr, y, 10); `+`(args) (y1 y2 y3 y4 y5 y6 y7 y8 y9 y10, , , , , , , , , ) →nargs > Kr(42, 47, 67, 89, 95, 62); ⇒ 67 |
В зависимости от х-значения А-процедура возвращает одну из процедур (активную в текущем сеансе) с именем, определенным вторым фактическим y-аргументом. Тогда как Fпроцедура, базирующаяся на parse-функции и реализованная однострочным экстракодом, возвращает n-арную процедуру (активную в текущем сеансе) с заданным именем f и ведущими переменными, начинающимися с x. В общем случае пусть Р – исходная конструкция, подлежащая созданию/модификации с последующим ее вычислением (активизацией) в текущем сеансе. На первом этапе обеспечивается вызов следующего формата: P1:= convert({P|eval(P)}, 'string')