Смекни!
smekni.com

Программирование и разработка приложений в Maple (стр. 74 из 135)

> sscanf(`2006 64 Abc 19.4264E+2 :Example `, ` %5d\%o\%x\%12e\%8s`);

[2006, 52, 2748, 1942.64, ":Example"]

> sscanf(`2006 64 Abc 19.4264E+2 :Пример`, ` %5d\%o\%x\%12e\%8s`);

[2006, 52, 2748, 1942.64, ":П"]

> sscanf("sqrt((sin(x) - gamma)/(tan(x) - Pi)) AVZ 64 Abc 19.4257E+2 :Example 21.09.2006", `%30a\%o\%x\%12e\%8s`);

Error, (in sscanf) incorrect syntax in parse: `;` unexpected (14)

> sscanf(`sqrt((sin(x)-gamma)/(tan(x)-Pi))AVZABCDEFG`, "%32a\%3c\%7[A-G]\%n");

 tansin( )( )xx − − πγ , "AVZ" "ABCDEFG" 42, ,  

> fscanf("C:\ARM_Book\Academy\Salcombe.IAN", "%16s\%5f\%a\%d\%n");

["Input_from_file:", 19.42, AVZ, 350, 65]

> Kr:= "Paldiski 23 april 2006": sscanf(Kr, "%s%d%s%d"); ⇒ ["Paldiski", 23, "april", 2006] > parse("sqrt((Art+Kr)/(VsV+VaA)+abs(Agn+Avz)-GAMMA*(Pi*Catalan)/20.06)"); Art + Kr

+

VsV + VaA Agn + Avz − 0.04985044865 Γ π Catalan

> fscanf("C:/ARM_Book/Academy/Lasnamae/Galina.52", "%15s %s %a");

["Input_Of_File", "25.03.99", RAC-IAN-REA-RANS]

> sscanf("RANS IAN", "%8s"), sscanf("x*A + y*B", "%9a"), sscanf("RANS IAN", "%8c");

["RANS"], [x A], ["RANS IAN"]

> sscanf("64, 47.59, 10.17, / 20.069", "%he"), sscanf("64, 47.59,\ 10.17 20.06", "%he");

[[64., 47.5900000000000034, 10.1699999999999999]], [[64., 47.5900000000000034,

10.1699999999999999, 20.0599999999999987]]

> map(type, [op(%[1]), op(%[2])], 'hfarray'); ⇒ [true, true]

> sscanf("[[64, 47.59], [ 10.17, 17.59]])", "%he"): type(op(%), 'hfarray'); ⇒ true > sscanf("2006", "%4D");

Error, (in sscanf) unknown format code `D`

В частности, использование средств данной группы с русскими текстами может приводить к некорректным результатам, как это иллюстрирует второй пример фрагмента для Maple 8. Средства для работы с выражениями string–типа полностью применимы и к выражениям symbol-типа, ибо один тип легко конвертируется в другой, и наоборот. Поэтому, в отношении функциональных средств данные типы можно считать эквивалентными. При этом, так как, начиая с 6-го релиза, строчное выражение является индексируемым, т.е. к отдельному его символу можно адресоваться по номеру его позиции (например, "abcddfg"[3], "abcddfg"[3..5]; ⇒ "c", "cdd"), то к такого типа выражениям применимы и многие стандартные средства пакета, предназначенные для работы с индексированными структурами данных.

Ниже средства Maple-языка пакета для работы со строчными и символьными данными и их структурами будут рассматриваться в различных контекстах при представлении иллюстративных примеров. При этом, следует отметить, что по представимости работы со строчными структурами Maple-язык располагает меньшим количеством функциональных средств, чем упоминавшийся выше пакет Mathematica, что предполагает несколько большую искушенность пользователя в этом направлении. Правда, с последними релизами поставляется пакетный модуль StringTools, содержащий набор средств для работы со строчными структурами. Его появление, по-видимому, было навеяно нашим набором средств подобного типа, созданным еще для Maple V (все наши издания по Mapleтематике хорошо известны разработчикам ввиду имевшего места сотрудничества в процессе подготовки этих изданий). Между тем, представленные в нашей Библиотеке [103,108,109] средства работы со строчными и символьными выражениями существенно дополняют имеющиеся средства пакета для задач подобного типа.

Например, во многих приложениях, имеющих дело со строчными выражениями, широко используется процедура Red_n, обеспечивающая сведение кратности вхождений символов или подстрок в строку или символ. Вызов процедуры имеет формат Red_n(S, G, N), где: S – строка или символ, G – строка или символ длины >= 1 или их список и N – положительное целое (posint) либо список целых положительных чисел.

Вызов процедуры Red_n(S, G, N) возвращает результат сведения кратности вхождений символов или строк, заданных вторым фактическим аргументом G в строку или символ, указанный первым фактическим S аргументом, к количеству не большему, чем третий аргумент N. В частности, если N={1|2}, то строка/символ G удаляется из строки S или остается с кратностью 1 соответственно. Кроме того, тип возвращаемого результата соответствует типу исходного фактического S аргумента. Процедура Red_n производит регистро-зависимый поиск. Если символ G не принадлежит строке S, то процедура возвращает первый фактический аргумент без обработки с выводом соответствующего предупреждения. Нулевая длина второго фактического аргумента G вызывает ошибочную ситуацию с диагностикой типа «length of <> should be more than 1».

Если второй и третий фактические аргументы определяют списки, между которыми существует взаимно-однозначное соответствие, то сведение кратности делается по всем элементам списка G с соответствующими кратностями из списка N. Если nops(G) > nops(N), последние nops(G) - nops(N) элементов G будут иметь кратности 1 в возвращаемом результате. Если G – список и N – положительное целое число, то все элементы G получают одинаковую кратность N. Наконец, если G – символ или строка и N – список, то G получает кратность N[1] в возвращаемом результате. Процедура Red_n представляет собой достаточно полезный инструмент для обработки строк и символов при символьном решении задач [103]. Ниже представлены исходный текст процедуры и некоторые примеры ее применения.

Red_n := proc(S::{string, symbol}, G::{string, symbol, list({string, symbol})}, N::{posint, list(posint)}) local k h, , Λ, , ,z g n; if type(G, {'symbol', 'string'}) then g := G; n := `if`(type(N, 'posint'), N, N[1]) else h := S; for k to nops(G) do try n := N k[ ]; h := procname(h, G k[ ], n) catch "invalid subscript selector": h := procname(h, G k[ ], `if`(type(N, 'list'), ,2 N))

catch "invalid input: %1 expects":

h := procname(h, G k[ ], `if`(type(N, 'list'), ,2 N))

end try

end do;

RETURN(h)

end if; `if`(length( )g < 1, ERROR "length of <%1> should be more than 1",( g), assign(z = convert([2], 'bytes')));

Λ := proc(S g n, , ) local a b h k p t, , , , , ;

`if`(search(S, g), assign(t = cat(convert([1], 'bytes') $ (k = 1 .. n − 1))),

RETURN(S,

WARNING("substring <%1> does not exist in string <%2>", ,g S)))

;

assign(h = "", a = cat "", ,( S t), b = cat "",( g $ (k = 1 .. n)), p = 0); do seq assign ' '( ( h = cat(h, `if`(a[k .. k + − n 1] = b, assign(' 'p = p + 1), a k[ ]))), k = 1 .. length(a) − + n 1);

if p = 0 then break else p := ;0 a := cat(h t, ); h := "" end if

end do;

h

end proc ;

if length( )g = 1 then h := Λ(S g n g, , , ) else h := Subs_All(z = g, Λ(Subs_All(g = z S, , 2), ,z n g, ), 2) end if;

convert(h, whattype(S))

end proc

> Red_n("aaccccbccccccccccccbcccccccckcccckccccccccccc", "cccc", 2);

"aaccccbccccbcccckcccckccccccc"

> Red_n("aaccccbbcccccccckcccckcccccccc", "cccc", 1); ⇒ "aabbkk"

> Red_n("1111122222233333334444444445555555556666666666", [`1`,`2`,`4`,`5`,`6`], [2,3,4,5,6]); "1223333333444555566666"

Не меньший интерес представляет и seqstr-группа процедур, обеспечивающих различные режимы конвертации последовательностей выражений в строку [41,103]. Например, простая процедура seqstr1, реализованная однострочным экстракодом вида:

seqstr1 := () -> cat("", op(map(convert, [args], 'string')));

обеспечивает конвертацию последовательности выражений в строку конкатенации этих выражений, например:

> seqstr1(), seqstr1(Z(x), x*y, (a + b)/(c + d), "ArtKr", 10/17)

"", "Z(x)x*y(a + b)/(c + d)ArtKr10/17"

Определенный интерес представляет и swmpat-группа процедур, обеспечивающих поиск образцов, содержащих wildcard-символы [103]. В качестве примера приведем swmpatпроцедуру. Вызов процедуры swmpat(S ,m, p, d {, h}) возвращает значение true, если и только если строка или символ, указанный фактическим аргументом S, содержат вхождения подстрок, которые соответствуют образцу m с группирующими символами, указанными четвертым аргументом d, тогда как третий фактический аргумент p определяет список кратностей соответствующих вхождений группирующих символов d в m.

Например, пусть триплет <"a*b*c", [4,7], "*"> определяет образец m="**** b ******* c". Вызов процедуры swmpat(S, m, [4, 7], "*") определяет факт вхождения в строку S непересекающихся подстрок, которые имеют вид образца m с произвольными символами вместо всех вхождений группирующего символа "*". При этом, если вызов процедуры swmpat(S, m, p, d, h) использовал необязательный пятый аргумент h и было возвращено значение true, то через h возвращается вложенный список, чьи 2-элементные подсписки определяют первые и последние позиции непересекающихся подстрок S, которые соответствуют образцу m. Кроме того, если образец m не содержит группирующие символы, то через h возвращается целочисленный список, чьи элементы определяют первые позиции непересекающихся подстрок S, которые соответствуют образцу m. Если же вызов процедуры возвращает значение false, то через h возвращается пустой список, т. е. [].

Если четвертый фактический аргумент d определяет строку или символ длины большей 1, то первый ее символ используется как группирующий символ. Если же список p имеет меньше элементов, чем количество вхождений группирующих символов в образец m, то избыточные вхождения получают кратность 1. По умолчанию, процедура swmpat поддерживает регистро-зависимый поиск, если вызов процедуры использует дополнительное ключевое insensitive-слово, то выполняется регистро-независимый поиск. Данная процедура имеет целый ряд весьма полезных приложений в задачах обработки строк и символов [103]. Ниже представлены исходный текст процедуры и примеры ее применения.

swmpat := proc( S::{string symbol, }, m::{string symbol, }, p::list(posint), d::{string symbol, }) local a b c C j k h s s1 m1 d1 v r res, , , , , , , , , , , , , , ν, n, ω, , , ,t ε x y; assign67(c = {args} minus {S d insensitive m p, , , , }, s = convert([7], 'bytes'), y = args);

C := (x, y) → `if`(member(insensitive, {args}), Case(x), x); if not search(m d, ) then h := Search2(C(S, args), {C(m, args)}); if h ≠ [ ] then RETURN(true, `if`(c = { }, NULL, `if`( type(c[ ]1 , 'assignable1'), assign(c[1] = h), WARNING( "argument %1 should be symbol but has received %2", c[1], whattype eval( [ ])( c 1 )))))

else RETURN(false)

end if

else

assign(ν = ((x, n) → cat(x $ (b = 1 .. n))), ω = (t → `if`(t = 0, 0, 1))); ε := proc(x y, ) local k; [seq(`if`(x k[ ] = y k[ ], ,0 1), k = 1 .. nops( )x )] end proc

end if; assign(s1 = cat "",( S), m1 = cat "",( m), d1 = cat "",( d)[1], v = [ ], h = "", r = [ ], res = false, a = 0); for k to length(m1) do

try if m1[k] ≠ d1 then h := cat(h, m1[k]); v := [op(v), 0] else a := a + 1; h := cat(h, ν(s, p a[ ])); v := [op( )v , 1 $ (j = 1 .. p a[ ])] end if catch "invalid subscript selector" := : h cat(h s, ); v := [op( )v , 1]; next end try end do; assign(' 'h = convert(C(h, args), 'list1'), 's1' = convert(C(s1, args), 'list1')), assign(t = nops( )h ); for k to nops(s1) − + t 1 do if ε(s1[k .. k + − t 1], h) = v then res := true; r := [op(r), [k, k + t − 1]]; k := k + t + 1

end if

end do; res, `if`(c = { }, NULL, `if` type(( c[ ]1 , 'assignable1'), assign(c[1] = r), WARNING "argument %1 should be symbol but has received %2" [( , c 1], whattype(eval(c[1])))))

end proc > S:="avz1942agn1947art1986kr1996svet1967art1986kr1996svet": m:="a*1986*svet": p:=[2,6]:

swmpat(S, m, p, "*", z), z; ⇒ true, [[15, 31], [36, 52]] > swmpat(S, "art1986kr", [7, 14], "*", r), r; ⇒ true, [15, 36] > swmpat(S, m, p, "*", 'z'); ⇒ true

> S:= "avz1942agn1947Art1986kr1996Svet1967Art1986kr1996Svet": m:= "a*1986*svet": p:= [2, 6]: swmpat(S, m, p, "*", a), a; ⇒ false, []

> S:= "avz1942agn1947Art1986Kr1996Svet1967Art1986Kr1996Svet": m:= "a*1986*svet": p:=[2, 6]: swmpat(S, m, p, "*", b, `insensitive`), b; ⇒ true, [[15, 31], [36, 52]]

> swmpat(S, "art1986kr", [7, 14], "*", t), t; ⇒ false, t

> swmpat(S, "art1986kr", [7, 14], "*", `insensitive`, 't'), t; ⇒ true, [15, 36]

Отметим еще одну довольно полезную процедуру работы со строчными выражениями. Процедура nexts(S,A,B {,r}) обеспечивает поиск в строке или символе, определенных фактическим аргументом S, образцов B, ближайших к образцам А справа или слева. Вызов процедуры с тремя аргументами определяет поиск вправо от А, тогда как вызов с четырьмя или более аргументами определяет поиск влево от A. Вызов процедуры nexts(S, A, B {, r}) возвращает вложенный список, элементами которого являются 2-элементные списки (если вложенный список содержит только один элемент, то возвращается обычный список). Первый элемент такого подсписка определяет позицию образца А в S, тогда как второй определяет позицию образца B, ближайшего к А вправо или влево соответственно. Более того, если ближайший к образцу А образец B не был найден, то возвращаемый процедурой список будет содержать только позицию самого образца. Кроме того, в качестве аргумента A может выступать как образец, так и позиция отдельного символа в S. Если второй аргумент A отсутствует в S, то вызов процедуры возвращает false. Если какой-либо фактический аргумент пуст, то вызов процедуры вызывает ошибочную ситуацию. Во многих задачах обработки символов и строк данная процедура оказалась довольно полезным средством и используется рядом процедур нашей Библиотеки [103,109]. Ниже представлены исходный текст процедуры и некоторые примеры ее применения.