8. Обработка на символна информация в Pascal. Символен тип и тип низ от символи. ASCII таблица в DOS. Операции с отделни символи и с низове от символи. Вградени подпрограми в Borland Pascal за работа със символи.

Освен за програми обработващи числени данни езикът Pascal може да се използва и за обработка на символни данни. В Pascal символните данни са три вида: отделни символи, низ от символи и текстов файл. Тук се разглежда работа с първите два вида символни данни.
 

Отделни символи в паметта на компютъра обикновено се кодират в един байт. Поради това те са 256 и на всеки символ съответна число - неговия код. В операционната система DOS тези символи са подредени в ASCII таблица. Тя включва малките и големите латински букви, цифрите, малките гръцки букви, препинателни знаци, псевдо-графични символи за изчертаване на таблици и блокове, управляващи знаци, букви с ударения използвани в разлени азбуки и др. Някои от управляващите символи са: 

Символите, които не са отбелязани на клавиатурата, могат да се въведат, като се държи натисват клавиша Alt и чрез цифрите в дясната част на клавиатурата се набере трицифрения код на символа.

В Windows символите зависят от шрифта с който се работи. Шрифтовете обикновено са подредени в ANSI таблица. Напоследък се използват разширени двубайтови шрифтове и тогава броят на символите е около 65000.

Оригиналната ASCII таблица и много от шрифтовете в Windows не съдържат кирилица. В ASCII таблицата тя се добавя чрез специална кирилизираща програма и обикновено започва от код 128. Тя се състои от общо 64 букви (големи и малки). Те заместват буквите с ударения и част от псевдо- графичните символи в оригиналната таблица. Съществуват обади други наредби на кирилицата както в DOS, така и в шрифтовете за Windows. Затова препоръчително е в програмата да се работи със самите символи, а не с кодовете на символите.

Символен тип. Това е вградения в Pascal тип char. На променливи от този тип в програмата може да се присвояват стойности чрез оператор за присвояване или чрез вход от клавиатурата. Символните константи, за които бе споменато във втора точка се задават чрез символа заграден с апострофи (напр. 'ж'). Символът апостроф се задава чрез четири символа апостроф по следния начин - ''''

Внимание: На клавиатурата има два символа апостроф: ляво наклонен и дясно наклонен. В Pascal се използва дясно наклонения, който е на един и същи клавиш с кавичката.

Символните данни могат да участват в операциите за сравнение. При това се извършва сравняване на кодовете на символите. Символният тип е изброим тип. В Pascal съществуват следните библиотечни функции за работа със символи

    function chr(kod: integer): char - преобразува число - код на символ в самия символ.
    function ord(ch: char): integer - преобразува символ в съответното му число - код на символа.
    function pred(ch: char): char - намира предходния символ в таблицата.
    function cucc(ch: char): char - намира следващия символ в таблицата.

Забележка: Всъщност последните три функции са за всякакви изброими типове.

Пример 8.1:

    var
        ch: char;
    begin
        ..............
        ch := 'Ж';                         { Присвояване на символ константа }
        readln(ch);                     { Въвеждане на символ от клавиатурата }
         if ch < 'Й'                      { Операция сравняване }
             then write(chr(7));     { Звуков сигнал }
        ...............
        { Преобразуване на големи букви кирилица в малки кирилица }
        if (ch >= 'А') and (ch<='Я')
             then ch := chr(ord('a') + ord(ch) - ord('А'));
        .............
    end.

Задача 8.1: Да се изведат на екрана всичките 256 символи.

Анализ
    Входни данни: няма.
    Изходни данни: 256 символа от кодовата таблица.Част от тях не могат да се видят (напр. управляващите).

Алгоритъм

    Начало
        За i <- 0 до 255 повтаряй
            Изведи chr( i )
    Край

Програма

program ascii;
    uses WinCrt;
    var i: integer;
    begin
         for i := 0 to 255 do begin
            write('Код ', i, '->символ ', chr( i ));
            readln
        end
    end.

Тип низ от символи. Низ от символи наричаме крайна наредена съвкупност от символи. Константен низ от символи (напр. 'Решение:' ), за който бе споменато във втора точка, представлява подредени един след друг символи, заградени с апострофи. Ако в низа има символа апостроф, той се пише два пъти (напр. 'Пролет''2000'). За тип низ от символи в Pascal има вграден тип string. Декларирането на променливи от този тип става по два начина:

    име: string;
    име: string[максимален_брой_символи];

При първия начин се подразбира, че максималният брой символи на низа е 255. При втория начин на деклариране максимален_брой_символи трябва да е цяла константа от 1 до 255. Когато се декларират параметри на подпрограми от тип низ от символи се ползва само първия начин на деклариране. От такъв тип са и функциите със стойност низ от символи.

Пример 8.2:

    var
        s: string;             { Максимална дължина 255 символа }
         s1: string[5];      { Максимална дължина 5 символа }

    function f1(a: string; var b: string): string;
        .......
        begin
            ......
         end;

Данните от тип низ от символи заемат в паметта толкова байта, колкото е тяхната максимална дължина плюс един.

Променливите от тип низ от символи могат да получават стойности чрез оператор за присвояване или чрез процедура за вход от клавиатурата. Стойността, която променливата може да приемат, е низ с дължина от 0 символа до максималната дължина на променливата. Низ с дължина 0 се нарича празен низ и се бележи с ''.

Пример 8.3 (виж пример 8.2):

    s := 'Иван';                    { Дължината на s е 4 символа }
    writeln('Име:', s:10);      { Извеждане на низ. s се извежда в 10 позиции }
    s1 := '';                           { На s1 се присвоява празния низ. Дължината е 0 символа }
    readln(s);                       { Въвеждане на низ от клавиатурата }
    s1 := 'Николай';            { Грешка! Низът 'Николай' е дълъг 7 символа. s1 се препълва. }

Низове могат да участват в операции за сравнение. Сравнението на два низа става по лексикографски начин т.е. първо се сравняват първите символи на двата низа, след това вторите и т.н. Всъщност се сравняват кодовете на съответните символи. Ако един низ изцяло се съдържа в началото на друг, то той е по-малък от него.

Пример 8.4:

    'Иван' < 'Петър'         =     true
    'Ана' < 'Анатолий'    =     true
    'Ана' < 'ана'               =     true    { главно 'А' е преди малко 'а' }

В Pascal съществува специална операция наречена конкатенация за слепване на низове. Конкатенация на два низа се задава чрез знака "+". Тази операция не е еквивалентна на събиране защото не е асоциативна ( 'Иван' + 'Петров' ¹ 'Петров' + 'Иван' ). Трябва да се внимава при слепване резултантния низ да не е по-дълъг от максималната дължина.

Пример 8.5:

    s := 'Иван'+' '+'Петров';     { Резултат: 'Иван Петров' }

Обръщението към отделните символи в един низ става чрез индекс. Първият символ е с индекс 1, вторият - с индекс 2 и т.н.

Пример 8.6:

    s:= 'Петров';
    s[4] := 'к';         { Резултат s = 'Петков' }

Променливите низове всъщност имат и символ с индекс 0. Кодът на този символ съответства на дължината на низа в съответната променлива. Например, ако s = 'Иван Петров', то ord(s[0]) = 11.

В Borland Pascal има няколко библиотечни подпрограми за работа с низове.

function length(s: string): string - определя дължината на низа s. Еквивалентна на ord(s[0]).

function concat(s1, s2, ..., sN: string): string - извършва операцията конкатенация Съществува за съвместимост с програми написани на по-старите версии на Pascal, където тази операция не се е поддържала.

function copy(s: string; index, broj: integer): string - взема под низ на низа s. Резултантния подниз започва от символ с индекс index и е с дължина broj.

procedure insert(subs: string; var s:string; index: integer) - вмъква низа subs вътре в низа s на позиция index. В резултат на това s става по-дълъг.

procedure delete(var s:string; index, broj: integer) - изтрива от низа s broj на брой символи от символа с индекс index нататък. В резултат на това s става по-къс.

function pos(subs, s: string): integer - търси отляво на дясно дали низът subs е подниз на низа s. Ако не е, резултатът е 0, иначе функцията връща индекса на първия символ на подниза subs в низа s. Например pos('Иван', 'Иво Иванов Иванов') = 5.

procedure str(x: числов; var s: string) - преобразува числото x в низа s. Към числото може да се приложат форматиращите модификатори за брой позиции и точност подобно на процедурите write и writeln за изход на екрана. Например, ако str(-3.14:6:3, s), тогава s = ' -3.140'.

procedure val(s: string; var x: числов; var code: integer) - преобразува низа s в числото x, ако е възможно. В s трябва да има низ изобразяващ правилно записано цяло или реално число. Допуска се и научен формат за запис на реалното число. При правилно преобразуване параметърът code = 0, иначе code дава индекса на този символ в s, който е предизвикал грешката.

Задача 8.2: Да се състави функция, която изчислява броя на думите в един низ.

Анализ
    Входен параметър: s - низ от символи.
    Резултат: n - цяло - броя на думите.

Алгоритъм: За да се броят думите, трябва да се определи, кои са разделителите между думите. Ще считаме че думите се отделят една от друга чрез: интервал, табулация, запетая. Лесно могат да се добавят и други разделители. Всички останали символи са букви от думите.

Функция

function brojdumi(s: string): integer;
    var
        i, n: integer;
        inw: boolean;     { Индикатор, дали сме вътре или вън от дума }
    begin
        inw := false;
        n := 0;
         for i := 1 to length(s) do
             if (s[i] = ' ') or (s[i] = chr(9)) or (s[i] = ',')     { Разделители между думи }
                then begin
                     if inw                             { За i - 1 сме били вътре в дума и сега излизаме }
                         then inw := false
                end
                 else if not inw                   { Влизаме в дума }
                    then begin
                        n := n + 1;
                        inw := true
                    end;
        brojdumi := n
    end;

Задача 7.3: Да се състави процедура за заместване на един подниз на даден низ с друг подниз.

Анализ
    Входни параметри: s1 - заместван подниз, lenght(s1) > 0;
                                       s2 - заместващ подниз, s2 ¹ s1;
                                      s - низ, в който се извършва заместването.
    Резултат: s.

Алгоритъм:

    Повтаряй
        Търси s1 в s
        Ако s1 е намерен
            Изтрий толкова символи в s, колкото е дължината на s1
            Вмъкни s2 на мястото на s1
    докато s1 се среша в s

Процедура

procedure replace(s1, s2: string; var s: string);
    var k:integer;
    begin
         if (length(s1) > 0) and (s2 <> s1)
            then repeat
                k := pos(s1, s);
                 if k > 0
                    then begin
                        delete(s, k, length(s1));
                        insert(s2, s, k)
                    end
              until k > 0
    end;


Съдържание


7. Подпрограми. Видове подпрограми в Pascal. Параметри на подпрограмите. Подпрограма процедура. Подпрограма функция. Локални и глобални величини в програмите. Предварително деклариране на подпрограма. Ползване на готови библиотеки от подпрограми. Рекурсия.


9. Записи. Деклариране и използване на записи. Запис - поле на друг запис. Вариантни записи. Оператор with.