Тип STRING b>
p>
Тип
STRING - це рядковий тип в Паскалі. Рядком називається послідовність
символів. Строковим константами ви вже неодноразово користувалися - це
послідовність будь-яких символів, укладена в апострофи; допускаються і
порожні рядки, вони записуються так:''. Рядкові змінні і типізовані
константи описуються у вигляді p>
STRING p>
або p>
STRING [максимальна довжина] p>
Якщо
максимальна довжина не задана, то за умовчанням вона береться рівною 255.
Максимальна довжина при описі строкових даних задається целочисленным
константним виразом і ніколи не може перевищувати 255. Це обмеження
обумовлено самою структурою типу STRING: фактично рядок - це масив ARRAY
[Byte] OF Char, причому в 0-м символі закодована поточна довжина рядка.
Рядкові змінні можуть мати будь-яку довжину від 0 до максимальної. У програмі
рядка можна використовувати і як єдиний структурований об'єкт (трохи пізніше ми
познайомимося з різноманітними можливостями обробки рядків), і як масив
символів, тобто звертатися до елементів рядків слід так само, як до елементів
масивів. Для рядків визначені наступні операції: p>
--
рядку можна присвоїти рядок; p>
--
рядка можна вводити процедурою READLN; p>
--
рядка можна виводити процедурою WRITE [LN]; p>
--
для рядків визначена операція зчеплення +, при цьому другий рядок дописується
праворуч до першої та довжина результату стає дорівнює сумі довжин операндів (якщо
вона не перевершує 255). p>
Запишемо
програму, що виконує найпростіші операції з рядками: p>
TYPE ShortString = STRING [80]; p>
VAR s1, s2: ShortString; s3: STRING; p>
BEGIN WRITE ( 'Введіть 1-й рядок');
READLN (s1); p>
WRITE ( 'Введіть 2-у
рядок '); READLN (s2); p>
WRITELN ( 'Ви ввели', s1, 'і', s2);
WRITELN ( 's1 + s2 =', s1 + s2); p>
s3: = s1 + s1 + s1; WRITELN ( 's1, повторена 3 рази', s3); p>
END. p>
Зверніть
увагу, що при введенні рядків завжди використовується READLN, але не READ. Процедура
READ на відміну від READLN зчитує лише символи до символу кінця рядка
(клавіша Enter), який залишається в буфері клавіатури. Таким чином, користуючись
процедурою READ можна ввести тільки один рядок; всі рядки, що вводяться слідом за
перше, стануть порожніми. Наприклад,
програма p>
VAR s1, s2: STRING; p>
BEGIN WRITE ( 'Введіть 1-й рядок');
READ (s1); p>
WRITE ( 'Введіть
2-й рядок '); READ (s2); p>
WRITELN ( 'Ви ввели "', s1, '" і "', s2 ,'"'); p>
END. p>
при
вхідному потоці abcdef Enter 123456 Enter виведе: Ви ввели "abcdef"
і "". Запишемо тепер програму, яка вводить деяку рядок,
замінює в ній всі цифри на пробіли та дописує в кінець рядка символи
"???": p>
VAR s: STRING; L, i: Byte; p>
BEGIN WRITE ( 'Введіть рядок'); READLN (s); p>
L: = ORD (s [0 ]); p>
FOR i: = 1 TO L DO IF s [i] IN ['0 '.. '9']
THEN s [i]: = ''; p>
FOR i: = L 1 TO L 3 DO s [i ]:='?'; p>
WRITELN ( 'Ось що вийшло:
', s); p>
END. p>
Наша
програма замінила цифри, але ніяких "?" не додала. Справа в тому,
що, звертаючись до елементів рядка, неможливо змінити поточну довжину рядка.
Другий цикл нашої програми спрацював правильно, записавши символи "?" в
відповідні елементи рядка, але довжина рядка залишилася колишньою, і процедура
WRITELN вивела тільки символи з 1-го по L-й. Щоб вирішити задачу коректно, ми
могли б додати в програму один оператор INC (s [0], 3); але, звичайно, краще
за все просто записати: s: = s +'???';. p>
Для
обробки рядків у Паскалі існує кілька стандартних функцій і процедур: p>
1. FUNCTION Length (S: String):
Integer; - повертає довжину рядка. P>
2.
FUNCTION Concat (S1 [, S2 ,..., Sn]: String): String; - повертає рядок,
отриману зчепленням аргументів, може використовуватися замість операції
"+". p>
3.
FUNCTION Pos (Substr: String; S: String): Byte; - повертає номер першого зліва
символу рядка S, починаючи з якого рядок Substr входить в S, якщо Substr НЕ
входить в S, то значення функції дорівнює 0. p>
4.
FUNCTION Copy (S: String; Index: Integer; Count: Integer): String; - повертає
підрядок рядка S, яка починається з символу з номером Index і має довжину
Count. P>
5.
PROCEDURE Delete (VAR S: String; Index: Integer; Count: Integer); - видаляє з
рядка S підрядок, що починається з символу з номером Index і має довжину
Count. P>
6.
PROCEDURE Insert (Substr: String; VAR S: String; Index: Integer); - вставляє в
рядок S підрядок Substr починаючи з символу з номером Index. p>
З
вищевикладеного зрозуміло, що процедури і функції можуть мати параметри типу
STRING (що дивно), а також допустимі функції типу STRING, хоча це і
НЕ скалярний тип. Ще дві стандартні процедури призначені для перекладу
рядка в число і числа в рядок: p>
7.
PROCEDURE Val (S: STRING; VAR V; VAR Code: Integer); - перетворить рядок S в
число V (якщо це можливо); V - будь-яка мінлива арифметичного типу,
мінлива Code повертає 0, якщо перетворення пройшло успішно, або номер
перший неправильного символу рядка. p>
8.
PROCEDURE Str (X [: Width [: Decimals]]; VAR S: STRING); - перетворить
довільне арифметичне вираз X в рядок S, параметри Width і Decimals
дозволяють форматувати рядок і мають такий же зміст, як і в процедурі
WRITE [LN]. P>
Тепер,
знаючи процедуру Val, ви можете організувати надійне введення числових даних у
будь-якій своїй програмі. Припустимо, що програма повинна вводити речовий
значення F. Ми можемо записати це так: p>
VAR F: Real; ... BEGIN WRITE ( 'Введіть F'); READ (F); p>
Якщо
користувач правильно введе число, то все буде гаразд, але якщо він
помилково натисне не ту клавішу (наприклад, кому замість точки і т.п.), то
станеться аварійне переривання, програма завершиться, і на екрані з'явиться
повідомлення "Run-time error ...". Програми, таким чином реагують
на невірний введення, - погані! Хороша програма зобов'язана обробляти натискання
практично будь-яких клавіш в будь-яких комбінаціях. Ми цілком здатні написати таку
програму: p>
VAR F: Real; S: STRING; Code: Integer; ... p>
BEGIN REPEAT p>
WRITE ( 'Введіть F'); READLN (S); p>
Val (S, F, Code); IF Code = 0
THEN Break; p>
WRITELN ( 'Помилка введення !'); p>
UNTIL FALSE; p>
Вирішимо
часто зустрічається завдання про розпакуванні тексту: дана рядок, що містить текст
російською мовою (або будь-якою іншою мовою, в тому числі і штучному - ви
побачите, що це не принципово); потрібно виділити слова, що містяться в цьому
тексті. Хоча це завдання і елементарна, її рішення не настільки тривіально і вимагає
попередньої розробки алгоритму. Спочатку з'ясуємо, що таке текст. Текстом
будемо називати послідовність слів, розділених будь-якою кількістю "прогалин".
Слова - це послідовності букв мови (у нашому випадку - російських букв),
"прогалини" - будь-які символи, які не є літерами. Отже, наш текст у
загальному випадку має вигляд: * X * X. ..* X *, де X - слово, * - "пробіл".
Можна запропонувати наступний алгоритм розпакування: p>
1)
видалимо завершальні прогалини, після чого текст візьме регулярний вид * X * X. ..* X; p>
2)
видалимо лідируючі прогалини; p>
3)
виділимо перше слово і видалимо його з тексту. p>
Після
виконання пунктів 2 і 3 ми отримали одне слово і текст став коротше на одне
слово, зберігши при цьому свою структуру. Очевидно, що пункти 2 і 3 слід
виконувати до тих пір, поки текст не порожній. Запишемо програму, що реалізує цей
алгоритм. p>
VAR
s: STRING; i: Byte; p>
CONST Letters: SET OF Char = [ 'а' .. 'п', 'р' .. 'я', 'А' .. 'Я']; (це алфавіт) p>
BEGIN WRITE ( 'Введіть текст'); READLN (s); p>
(Видалимо завершальні прогалини, тут є 1 ПОМИЛКА! ) p>
WHILE NOT (s [Length (s)] IN Letters) DO Delete (s, Length (s), 1); p>
WRITELN ( 'Слова тексту :'); p>
(організовуємо цикл ЗА СЛОВАМИ) p>
WHILE s <>''DO BEGIN p>
(видалимо лідируючі прогалини) p>
WHILE NOT (s [1] IN Letters) DO Delete (s, 1,1); p>
(знайдемо кордон першим
слова, тут є 1 ПОМИЛКА! ) p>
i: = 1; WHILE s [i] IN Letters DO INC (i); p>
(i - номер перший
пробілу) p>
Dec (i); p>
(виведемо слово) p>
WRITELN (Copy (s, 1, i )); p>
(видалимо слово з тексту) p>
Delete (s, 1, i); p>
END; p>
END. p>
На
перший погляд наша програма працює правильно (ми ввели фразу українською
мовою і отримали всі слова з неї), але тестування програми обов'язково
повинно включати всі граничні, або особливі, випадки. Введемо, наприклад,
рядок, що не містить ніяких слів, і програма зациклиться! Це результат
помилки в першому циклі: якщо в тексті немає букв, всі символи з нього будуть
вилучено, довжина рядка стане рівною нулю, і надалі стане перевірятися
символ з номером 0, що дорівнює # 0 і, природно, не є літерою. Ще
одна помилка подібного роду може статися при виділенні останнього слова: ми
збільшуємо індекс i, поки i-й символ - буква, і врешті-решт дійдемо до кінця
рядка. Але мінлива s завжди містить 255 символів, символи з номерами
Length (s) +1, Length (s) 2 і т.д. існують, і немає жодних гарантій, що вони не
є російськими літерами. У цьому випадку ми можемо отримати останнє слово з
"хвостом". Виправимо нашу програму: p>
VAR s: STRING; i: Byte; p>
CONST Letters: SET OF Char = [ 'а' .. 'п', 'р' .. 'я', 'А' .. 'Я']; (це алфавіт) p>
BEGIN WRITE ( 'Введіть текст'); READLN (s); p>
(Видалимо завершальні прогалини) p>
WHILE NOT (s [Length (s)] IN Letters) AND (s <>'') DO
Delete (s, Length (s), 1); p>
IF s =''THEN BEGIN WRITELN ( 'текст порожня'); Halt;
END; p>
WRITELN ( 'Слова тексту :'); p>
(організовуємо цикл ЗА СЛОВАМИ) p>
WHILE s <>''DO BEGIN p>
(видалимо лідируючі прогалини) p>
WHILE NOT (s [1] IN Letters) DO Delete (s, 1,1); p>
(знайдемо кордон перші слова) p>
i: = 1; WHILE (s [i] IN
Letters) AND (i <= Length (s)) DO INC (i); p>
(i - номер першого пробілу
) p>
Dec (i); p>
(виведемо слово) p>
WRITELN (Copy (s, 1, i )); p>
(видалимо слово з тексту) p>
Delete (s, 1, i); p>
END; p>
END. p>
Тепер
запишемо те ж саме, використовуючи функції та процедури: p>
VAR s: STRING; i: Byte; p>
CONST Letters: SET OF Char = [ 'а' .. 'п', 'р' .. 'я', 'А' .. 'Я']; (це алфавіт) p>
PROCEDURE DelTail (VAR s: STRING); p>
BEGIN WHILE NOT (s [Length (s)] IN
Letters) AND (s <>'') DO Delete (s, Length (s), 1); END; p>
PROCEDURE DelLead (VAR s: STRING); p>
BEGIN WHILE NOT (s [1] IN Letters) DO
Delete (s, 1,1); END; p>
FUNCTION MakeWord (s: STRING; VAR
Bound: Byte): STRING; p>
BEGIN Bound: = 1; p>
WHILE (s [Bound] IN Letters) AND (Bound <= Length (s)) DO INC (Bound); p>
Dec (Bound); MakeWord: = Copy (s, 1, i); END; p>
BEGIN WRITE ( 'Введіть текст'); READLN (s); p>
(Видалимо завершальні прогалини) p>
DelTail (s); p>
IF s =''THEN BEGIN WRITELN ( 'текст порожня'); Halt;
END; p>
WRITELN ( 'Слова тексту :'); p>
(організовуємо цикл ЗА СЛОВАМИ) p>
WHILE s <>''DO BEGIN p>
(видалимо лідируючі прогалини)
DelLead (s); p>
(виведемо слово) WRITELN (MakeWord (s, i )); p>
(видалимо слово з тексту)
Delete (s, 1, i); p>
END; p>
END. p>
Список літератури h2>
Для
підготовки даної роботи були використані матеріали з сайту http://elib.albertina.ru/
p>