Тема: Обробка символьної інформації.
 Формування і використання текстових файлів
  
 Теоретичні відомості щодо виконання лабораторної роботи
  
 Тип даних String. Із символів складаються слова, з яких, у свою чергу, складаються речення (рядки) і так далі. Для опису символьної інформації у мові Pascal існує тип Char. Для опису даних рядкового типу в мові Pascal передбачено службове слово String, за яким у квадратних дужках вказується довжина рядка. Максимальна довжина рядка дорівнює 255 символів. Тобто біжуче значення довжини рядка може бути будь-яким - у межах від 0 до 255 символам. Якщо не зазначити довжину рядка, то за замовчанням довжина рядка стає максимальною.
 Дані рядкового типу можуть бути описані у розділах Const, Type та Var.
 П р и к л а д
					Const
					adress = 'Першотравнева, 20';
					Type
					Str_Type = String[20];
					Var
					 s1 : Str_Type;
 s2, s3: String[10];
 s4 : String;
  
 Слід зазначити, що в разі, коли поле (довжина рядка) менше від самого рядка, рядок укорочується праворуч таким чином, щоб він умістився в полі.
 До символів, які складають рядок, можливий доступ як до елементів масиву.
 Над рядками визначено всі операції відношення. Порівняння рядків виконується попарно для відповідних символів двох рядків - зліва направо. Наприклад, 'pascal' > 'Pascal' обумовлює результат True, а результат 'PASCAL' > 'pascal' - False, оскільки порядкові номери малих букв більші від великих. У рядках різної довжини кожний символ із довшого рядка, що не має відповідного символу в короткому, виробляє значення 'більше'.
  
 Процедури та функцiї обробки рядків.
 Функція Length(s:String):Integer - як аргумент дістає рядок s і повертає його довжину.
 Слід зазначити, що перший символ рядкової змінної (індекс 0) містить динамічну довжину рядка. Таким чином, якщо s - змінна рядкового типу, то значення Length(s) завжди дорівнює Ord(s[0]).
 Функція ConCat(s1, s2, …, sn):String - як аргументи дістає кілька рядків s1, s2, …, sn послідовно з’єднує їх і повертає результат. Альтернативою цій функції є операція '+'.
 Функція Copy(s:String; Index:Integer; Count:Integer):String - дістає як аргументи рядок s, номер позиції Index і довжину підрядка Count. У результаті з рядка, починаючи з позиції Index, вилучається підрядок довжиною Count.
 Функція Pos(SubStr:String; s:String):Byte - дістає як аргументи рядки SubStr і s та повертає позицію, з якої підрядок SubStr перший раз зустрічається в рядку s.
 Процедура Delete(Var s:String; Index:Integer; Count:Integer) - видаляє з рядка s підрядок, починаючи з позиції Index довжиною Count символів.
 Процедура Insert(Var Source:String; Var s:String; Index:Integer) - вставляє рядок Source у рядок s, починаючи з позиції Index.
 Для перетворення чисел у рядки й навпаки призначені процедури Str і Val.
 Процедура Str(x [:Width [:Decimals]]; Var s:String) - перетворює число х у рядок s. Параметри Width і Decimals виконують таку саму роль, що і в операторі Write. Квадратні дужки позначають необов’язковість того, що в них укладено.
 Процедура Val(s:String; Var v; Code:Integer) - перетворює рядок s у значення числової змінної v. Рядок s повинен бути коректним записом числа. Якщо це так, змінна Code = 0 - перетворення виконано успішно. Якщо це не так змінна Code ¹0 - перетворення не виконано, а змінна Code має значення тієї позиції, в якій перетворення неможливе.
 П р и к л а д
 Program DemoWorkString;
 {Програма демонструє використання процедур
  та функцій при обробки символьної інформації }
					Var
					S,S1,S2,S3,S4,S5:String;
 V:Real;
					Begin
					S1:='Мова ';S2:='Система';S3:='програмування ';
 S4:='Turbo Pascal';
 V:=7.0;
  
 S5:=Copy(S4,Length(S4)-5,7);
 WriteLn(S5); {'Pascal'}
  
 Delete(S4,Length(S4)-5,7); {'Turbo '}
 WriteLn(S4);
  
 S:=ConCat(S1,S3,S5);
 WriteLn(S); {'Мова програмування Pascal'}
  
 S:=Copy(S,6,Length(S));
 WriteLn(S); {'програмування Pascal'}
  
 S:=S2+' '+S;
 WriteLn(S); {'Система програмування Pascal'}
  
 Insert(S4,S,Pos('P',S));
 WriteLn(S); {'Система програмування Turbo Pascal'}
  
 Str(V:4:1,S1);
 S:=S+S1;
 WriteLn(S); {'Система програмування Turbo Pascal 7.0'}
  
 ReadLn;
 End.
  
 Загальні відомості застосування файлів. У мові Pascal підтримується три файлових типи:
 - текстові файли (тип Text);
 - типізовані файли (тип File of);
 - нетипізовані файли (File).
 У програмі кожному зовнішньому файлу (файл на диску ніяк не описується, він має тільки ім’я) ставиться у відповідність (обов’язково описується у програмі) або явно в розділі змінних, або (ще краще) в розділі типів файлова змінна, певного типу:
 або
 Type <ім’я файлового типу> : <тип файлу>;
 Var <ім’я файлової змінної> : < ім’я файлового типу >;
 або
 Var <ім’я файлової змінної> : <тип файлу>;
  
 Наприклад,
					Type
					 f_Txt:Text;
 f_FileOf:File of Real;
 f_File:File;
					Var
					f1 : f_Txt;
 f2 : FileOf;
 f3 : f_File;
 f_int : File of Integer;
 f_sym : Text;
  
 Процедури загального використання для роботи з файлами будь-якого типу.
 Assign(f, Name) - ставить у відповідність файловій змінній f зовнішній файл з іменем Name.
 Reset(f) - відкриває вже існуючий файл f для читання та позиціонує покажчик файла на його початок.
 Rewrite(f) - створює та відкриває новий файл f, покажчик файла встановлюється на його початок. Якщо цю процедуру застосувати до вже існуючого файлу, то вміст цього файлу зникне.
 Close(f) - закриває файл (тобто операція "закрити" є логічним завершенням роботи з відкритим файлом, іншими словами - застосування процедури Close дозволяє усунути зв’язок файлової змінної із зовнішнім файлом, який встановлено процедурою Assign).
 Erase(f) - знищує файл f, який перед тим треба закрити.
 Rename(f, s) - перейменовує файл f в файл s, який перед тим треба закрити.
  
 Текстові файли (тип Text). Текстовi файли - це файли, що являють собою послідовність символів, які розбиті на рядки. Кожний рядок закінчується маркером кінця рядка. Текстовi файли належать до файлів з послідовним доступом (більш подрібни відомості роботи з файлами наведені в наступній лабораторній роботі).
 Для роботи з текстовим файлом необхідно, перш за все, описати відповідну файлову змінну або у розділі Type, або у розділі Var, наприклад:
 Var <ім’я файлової змінної> : Text;.
  
 Робота з текстовим файлом проводиться за схемою:
 - у відповідність файловій змінній ставиться ім’я зовнішнього файлу (процедура Assign);
 - відкривається новий текстовий файл (процедураRewrite) або вже існуючий (процедураReset). У кожний момент роботи з текстовим файлом допускається будь-який один тип операції: читання або запис;
 - обробка текстового файлу;
 - закриття файлу (процедура Close).
 Для зчитування інформації з файлу (який відкритий процедуроюReset) використовуються процедури Read(f, <список вводу>) і ReadLn(f, <список вводу>). Тобто, якщо перед списком вводу стоїть файлова змінна, то дані вводяться не з клавіатури, а зчитуються з файлу. Різниця між Read і ReadLn в тому, що Read читає дані з файлу без переходу на наступний рядок, а процедура ReadLn забезпечує такий перехід.
 П р и к л а д.
 Var f : Text;
 a, b, c : Integer;
 …………………
 Read(a, b, c); {ввід з клавіатури}
 Read(f, a, b, c); {ввід (зчитування) з файлу}
  
 Після відкриття покажчик файлу вказує на перший символ файлу. Зчитування чергової порції даних завжди виконується, починаючи з символу, на який вказує покажчик. Після зчитування покажчик файлу автоматично пересувається вперед на довжину прочитаної ділянки.
 Запис у текстовий файл (який відкритий процедуроюRewrite) виконується процедурами Write(f, <список виводу>) і WriteLn(f, <список виводу>), в яких перед списком виводу стоїть файлова змінна. Процедура і WriteLn записує інформацію до поточного рядка з переходом у наступний.
 П р и к л а д. Обчислити вираз  на інтервалі
 на інтервалі  з кроком
 з кроком  при
 при  . Результати обчислень записати у текстовий файл "file.dat".
 . Результати обчислень записати у текстовий файл "file.dat".
 ProgramExample_1;
					Const
					a=0.5; b=1.2; {параметри, що входять у склад виразу}
 tn=0; tk=2; h=0.2; {[tn, tk] - межі зміни аргументу виразу}
 {h - крок, з яким змінюється аргумент}
 NameFie='file.dat';
					Var
					f: Text;
 t, y: Real; {значення аргументу та виразу}
 FunctionFunc(x:Real):Real;
					Begin
					Func:=a*Exp(Sin(b*x))
 End;
					Begin
					Assign(f, NameFile); {якщо NameFile=' ' (-пусто) - вивід
 на екран }
 Rewrite(f);
 t:=tn;
					Repeat
					WriteLn(f, t:3:1,' ':2, Func(t):8:4);
 t:=t+h;
 Untilt>tk+h;
 Close(f);
 End.
  
 Дані, які зберігаються у текстовому файлі "file.dat" (у вигляді двох стовпців) доступні для обробки не тільки Pascal-програмами, а й іншими пакетами.
 При роботі з текстовими файлами дозволено використовувати процедуру Append(f), яка відкриває вже існуючий текстовий файл і позиціонує покажчик на кінець файлу. Після такого відкриття текстового файлу його можна тільки доповнювати інформацією, починаючи з кінця файлу.
  
 Спеціальні функцій обробки інформації текстових файлів:
 Eoln(f) - повертає значення True, якщо покажчик файлу вказує на кінець рядка (код #13#10), інакше - значення - False.
 Eof(f) - повертає значення True, якщо покажчик файлу вказує на кінець файлу (код #26), інакше - значення - False.
 IOResult(f) - перевіряє результат виконання останньої операції введення/виведення на наявність помилок. Функція повертає ціле значення, що є станом останньої виконаної операції введення/виведення.
 Слід зазначити, що функцію IOResult, можна використовувати для перевірки існування файлу на диску. Тобто, при зчитуванні інформації з файлу (будь-якого, не тільки текстового) було б правильно переконатися (безпосередньо у програмі), що файл дійсно існує на диску і нормально відкритий. Для цього перед відкриттям файлу необхідно виключити директиву компілятора {$І+}, тобто необхідно вказати {$І-}. У цьому випадку функція IOResult, набуває значення 0 при успішному відкритті файлу і відмінне від нуля значення - код помилки, якщо файлу на диску немає або до нього немає доступу (вказано невірний шлях до нього).
 П р и к л а д. Зчитування інформації з текстового файлу "file.dat" створеного програмою Example_1 і ввід її на екран дисплея.
 ProgramExample_2;
 Varf :Text;
 t, y :Real;
 Assign(f,'file.dat');
 {$I-} {виключити обробник помилок}
 Reset(f);
 {$I+} {включити обробник помилок}
 If IOResult=0Then
					Begin
					WriteLn('Файл існує і нормально відкритий');
 While Not Eof(f)do
					Begin
					ReadLn(f, t, y);
 WriteLn(t:3:1,' ':2,y:8:4);
 End;
 Close(f);
					End
					Else WriteLn('Проблеми! Такого файлу на диску не знайдено');
 End.
  
 П р и к л а д. Даний текст. Визначити кількість слів тексту за умови, що одне слово від іншого можу бути відокремлене пробілом, комою чи крапкою. Всі роздільники слів замінити символом підкреслення. У новий файл вивести по 5 слів у рядку.
 Program Example_3;
 Var {кількість:}
 iSymbol, {символів у слові}
 iWord, {слів у тексті}
 n:Integer; {слів у рядку}
 s:Char; {введений символ}
 str:String; {рядок, який формується}
 f1,f2:Text; {файли: початковий, робочий, протоколу}
					Begin
					Assign(f1,'file.txt');Reset(f1);
 Assign(f2,'file_r.txt');Rewrite(f2);
 WriteLn(f2,'П О Ч А Т К О В Ы Й Ф А Й Л':30);
 While Not Eof(f1) do{копіювання файлу f1 у файл f2}
 Begin ReadLn(f1,str);WriteLn(f2,str); End;
 iSymbol:=0;iWord:=0;n:=0;str:='';
 WriteLn(f2,' О Б Р О Б Л Е Н И Й Ф А Й Л':30);
 Reset(f1); {перевідкриття файлу f1}
 While Not Eof(f1) do
 Begin {читання з файлу f1}
 Read(f1,s);
 If (s=' ') And (iSymbol=0) Then Continue; {пропуск пробілів}
 If EoLn(f1) Or (s In [' ', ',' , '.'])
					Then
					Begin {виявлено кінець рядка або слова}
 If EoLn(f1) Then
 Begin { виявлено кінець рядка }
 str:=str+s; {приєднання останнього символу}
 ReadLn(f1); {перехід на наступний рядок}
 WriteLn(f2);
 End;
 str:=str+'_';Write(f2,str); {запис чергового слова}
 n:=n+1; iSymbol:=0;str:='';iWord:=iWord+1;
 If n=5 Then Begin n:=0; WriteLn(f2) End;
					End
					Else Begin str:=str+s;iSymbol:=iSymbol+1 End
 End;{While}
 WriteLn(f2,#10#13,'Кількість зчитаних слів = ',iWord,#10#13,);
 Close(f1);Close(f2);Reset(f2);
 While Not Eof(f2) do
 Begin ReadLn(f2,str);WriteLn(str); End;
 Close(f2);
 End.
  
 Контрольні питання
  
 1. Яка різниця між рядковою змінною та масивом символів?
 2. Як описуються рядкові змінні у програмі?
 3. Яка максимально допустима довжина рядка в мові Pascal?
 4. Які процедури та функції обробки рядків містить мова Pascal?
 5. Засоби виводу змінних рядкового типу.
 6. Які файли називаються текстовими? Принципи роботи з текстовими файлами.
 7. Що являє собою файлова змінна?
 8. Процедури та функції обробки текстових файлів. Особливості їх застосування.
 9. Як у програмі організувати перевірку результату відкриття існуючого файлу?
  
 Завдання та пояснення щодо виконання до лабораторної роботи
  
 Розробити функціональну схему, опис алгоритму і програму для символьної інформації відповідно до варіанту завдання.
 В кожному завданні початковим є файл з текстом, що складається з декількох речень. Слова в реченні розділяються пробілами і розділовими знаками (наприклад, крапкою, комою, ?, !). Тексти початкових даних формуються самостійно, але так, щоб було можливо оцінити працездатність програми.
 За кожнім варіантом завдання необхідно:
 - створити початковий текстовий файл (будь-яким чином) ;
 - згідно з варіантом завдання виконати обробку початкового файлу і зберегти отримані результати у новому текстовому файлі;
 - вивести дані з нового файлу з протоколом тестування (заголовки кожного етапу обробки даних, початкові та результуючі дані ).
 
 Варіанти завдань
  
 Варіанти обробки символьної інформації (текстів) дано у вигляді трьох груп (I, II, III) у порядку зростання їх складності.
  
 Варіанти завдань групи I
 1. Визначити і вивести: а) кількість речень і слів кожного речення; б) текст кожного речення в окремому рядку.
 2. Дана літера. Визначити кількість слів у тексті, які починаються з цієї літери. Вивести ці слова і їх кількість.
 3. Даний підрядок з двох (трьох) символів. Підрахувати, скільки разів зустрічається у тексті цей підрядок. Вивести ці слова.
 4. Даний символ. Знайти і видалити його з усіх слів тексту. Текст, що залишився, "стиснути".
 5. Даний підрядок з двох (трьох) символів. Знайти у тексті заданий підрядок і видалити його з усіх слів тексту. Текст, що залишився, "стиснути". Визначити кількість видалених підрядків.
 6. Визначити кількість слів тексту, які починаються і закінчуються на одну й ту саму букву. Вивести ці слова та їх кількість.
 7. Дано 2 літери. Знайти у тексті перший заданий символ і замінити його другим заданим символом. Визначити кількість замін.
 8. Дано 2 підрядки, кожний з двох (трьох символів). Знайти у тексті слова, що мають підрядок, який співпадає з першим підрядком, і замінити його другим заданим підрядком.
 9. Дано 2 слова. Визначити, чи є вони у тексті й скільки разів кожне з них зустрічається у тексті. Якщо їх у тексті немає, дати відповідне повідомлення.
 10. Виділити з початкового тексту частини тексту, які укладені у круглі дужки, включаючи й їх; вкладених дужок немає. Визначити кількість таких частин тексту і в кожному з них кількість російських букв, кількість латинських букв і цифр.
 11. Сформувати "перевертиш" від кожного слова тексту із допомогою підпрограми.
  
 Варіанти завдань групи II
 1. Визначити, скільки слів тексту мають довжину 1, 2, 3, …, 10 і більше 10 символів. Вивести ці слова у порядку зростання їх довжини.
 2. Дано символ. Визначити і вивести слова, у яких зустрічається цей символ, і номер позиції, в якій він розміщений у слові перший раз.
 3. Дано підрядок з двох (трьох) символів. Визначити і вивести слова, в яких зустрічається цей підрядок, і номери позицій слів тексту, починаючи з яких розміщується цей підрядок.
 4. Дано n і k - номера рядка і позиції у рядку. Дано рядок для вставки його у текст. Вставити заданий рядок у текст після k-го символу n-го рядка початкового тексту. Текст, який залишився, вивести з нового рядка.
 5. Виділити з тексту цілі числа й визначити їх кількість.
 6. Дана таблиця кодування символів. Зашифрувати посимвольно заданий текст. Вивести зашифрований текст. Ввести, розшифрувати зашифрований текст й вивести його.
 7. Визначити складність кожного речення й всього тексту. Складність речення оцінити за кількістю його слів і кількістю розділових знаків. Кожне речення вивести з нового рядка; після нього надрукувати (на екрані) характеристики його складності. Складність усього тексту визначити за кількістю його слів і за кількістю його речень.
 8. Дано 2 тексти (у двох різних файлах). Знайти у другому тексті всі "перевертиши" слів першого тексту.
 9. Дано список прізвищ з ініціалами. Визначити, чи є у списку однакові прізвища (ініціали не враховувати). Вивести список однакових прізвищ, кількість однофамільців з кожного прізвища і загальну кількість однофамільців.
  
 Варіанти завдань групи III
 1. Визначити у тексті кількість попадань кожної голосної і кожної приголосної букви. Впорядкувати голосні й приголосні у порядку зменшення частоти (кількості) використання їх у тексті.
 2. Визначити, які символи і скільки разів зустрічаються у тексті. Впорядкувати їх у порядку зменшення частоти (кількості) використання їх у тексті.
 3. Визначити і вивести символи, з яких починаються слова у тексті в порядку частоти (кількості) вжитку їх у тексті.
 4. Визначити різні слова у тексту і кількість разів зустрічей кожного слова. Впорядкувати ці слова у порядку зменшення частоти (кількості) використання їх у тексті.
 5. Визначити різні слова тексту та їх кількість. Сформувати таблицю кодування слів випадковими цілими числами. Зашифрувати заданий текс за словами і вивести його у файл. Ввести, розшифрувати зашифрований текст й вивести його.
 6. Знайти у тексті слова, довжина яких більше 5 символів і які зустрічаються у тексті більше трьох разів, замінити їх кодом (спеціальним символом). У кожного слова повинен бути свій код. За рахунок заміни стиснути текст.