Читать книгу: «Искусственный интеллект. Строки, контекст и волны на Паскале», страница 3

Шрифт:

Кодировки

Ввод данных в стандартном окне программы DOS осуществляется в кодировке DOS ASCII. Также и данные, которые в нем отображаются, имеют кодировку DOS.

В случае, если нам требуется обрабатывать данные из какого-либо внешнего источника, например из приложения «Блокнот», скорее всего, потребуется перекодирование из Win-кодировки. «Скорее всего» поскольку символы цифр, пробелов, пунктуации и английских букв имеют одинаковые адресные значения как в кодировке Win, так и в DOS; но символы дополнительных языков, например кириллицы, имеют различные значения в различных кодировках. Между тем если и вывод и ввод осуществляется в фоновом режиме, и как исходные данные так и обрабатываемые находятся в одной кодировке, перекодирование из одной кодировки в другую также может и не потребоваться. (Например, в случае, когда мы принимаем в обработку данные, записанные в кодировке Win, и записываем их часть в другой файл, имеющий ту же кодировку Win).

Для разбора кодировки символов нам понадобится следующая пара функций:

CHR (x) – указывает на символ с числом X из символьной таблицы (это можно сделать и служебным обозначением «#x», например K:=#32, — в данном случае, значение k будет равно пробелу, символу с кодом «32» в соответствии с таблицей символов ASCII).

ORD (k) – возвращает код символа K из символьной таблицы.

Здесь, K имеет тип Char (символ). Операции с символами схожи с операциями со строковым типом, например к переменной строчного типа мы можем добавить символ:

S:=S+K;

Здесь, если содержимое S=«Мама мыла раму», а K=«c», мы получим значение S=«Мама мыла рамуc»;

Значения таблицы символов по величине равны одному байту, следовательно, они могут принимать численные значения в диапазоне от 0 до 255.

Чтобы вывести стандартную таблицу символов, нам понадобится следующая программа:

Илл. 12. Программа для вывода таблицы символов ASCII DOS.


Мы несколько усложнили ее для того, чтобы получить ровную таблицу: здесь мы выделили код символа другим цветом, и добавили символы: «0» к двузначным и «00» однозначным числам.

Так мы выводим значения таблицы символов ASCII в DOS-кодировке, кроме управляющих символов с кодами «11» («vertical tab»/ «вертикальная табуляция»), «12» («form feed»/ «смена страницы») и «13» («Enter»). Также был «испорчен» управляющий символ «8», равнозначный команде удаления предыдущего символа с клавишей «Backspace».26


Илл. 13. Результат вывода таблицы символов в программе Tabsym.


Здесь, символы с кодами до 32 являются служебными.

Кстати, из управляющих символов в будущем нам могут понадобиться:

«Тab» – #9

«Enter» – #13

и возможно, «Esc» – #27.

Несмотря на то, что они не имеют явного представления в виде конкретного обозначения, но они так же записываются в тексте, как и все остальные. То есть, взглянув на строку мы не увидим что там есть символ с кодом «13» («Enter»), но при обработке этой строки последним символом может оказаться символ с кодом «13». Это особенно важно понимать при обработке предварительно сохраненных файлов.

Что в этой таблице является очевидным: мы можем выделить значения чисел от 0 до 9 (коды 48—57); ряд символов пунктуации и специальных знаков (коды 33—47); английские прописные (большие) буквы от A до Z (коды 65—90); английские строчные (маленькие) буквы от a до z (коды 97—122); русские прописные (большие) буквы от А до Я (коды 128—159); русские строчные (маленькие) буквы от а до я (коды 160—175, 224—239) отдельно буквы Ё (240) и ё (241); и элементы псевдографики (коды 176—223).

Для простоты восприятия на рисунке ниже представлена нумерация кодов клавиш стандартной клавиатуры «QWERTY».


Илл.14. Стандартный набор кодов клавиатуры «Qwerty».


На следующем рисунке приведена базовая кодировка ASCII в двоичном, восьмеричном и символьном коде без использования дополнительных языков.


Илл. 15. Различные характеристики кодов ASCII-таблицы символов.




Справка:

ASCII (англ. American standard code for information interchange), – название таблицы кодировки, в которой распространённым печатным и непечатным символам сопоставлены числовые коды. Таблица была разработана и стандартизована в США, в 1963 году.

Так или иначе, если в программе нужно использовать какой-то символ, например для условия выхода из цикла, уточнить его нам поможет простая программа:


Илл.16. Программа вывода кодов символов «по требованию» пользователя: код нажатой клавиши будет отображаться на экране.


Здесь, Key – переменная символьного типа Char отвечает за нажатие клавиш и последующий вывод кода символа на экран.

Строка «If keypressed=true» – «Если нажата клавиша», то переменной «key» присваивается символ нажатой клавиши «readkey». Затем, мы выводим на экран значение символа в таблице (функция ord) и сам символ (key).

Пример ее использования:


Илл. 17. Программа сообщает коды нажатых пользователем клавиш.


Итак, мы разобрались с таблицей символов.

Теперь поговорим о перекодировке.

Как уже упоминалось, Win-кодировка текстового файла отличается от DOS-кодировки, но она необходима для получения данных из открытых источников и удобства представления данных.

Нормализация строк

Для перекодировки строки текста из кодировки Win в DOS нам потребуется следующая процедура DecodeToDOS:


Илл. 18. Процедура для декодирования строки из стандартной кодировки Win в DOS.


Соответственно, обратно из кодировки DOS мы можем «перегнать» текст в кодировку Win (например, для записи в файл).


Илл. 19. Процедура для декодирования строки из стандартной кодировки DOS в кодировку Win.


Также, нам может потребоваться перекодирование не строки (из Win в DOS), а отдельного символа, в этом случае мы используем процедуру DecodeToDOSC:


Илл. 20. Преобразование из кодировки Win в кодировку Dos отдельного символа.


В программах использующих перекодировку символов мы использовали простой принцип преобразования, обращаясь к числовым значениям переменных.

Далее, говоря об обработке строковых данных нам регулярно будет требоваться процедура замены подстроки в строке, как приведенная ниже InsInString:


Илл. 21. Замена подстроки в строке на нужный набор символов в процедуре InsInString происходит благодаря несложной конструкции из функций Pos, Length и Copy.


Как она работает. Переменная i получает позицию нахождения подстроки S2 в строке S. Если при этом позиция находится не на первом символе, в строку результата S4 копируется фрагмент строки до указанной позиции (фрагмент Copy (S,1,i-1), к нему прибавляется «слово» -замена S3, и оставшийся фрагмент текста за минусом уже полученного фрагмента с учетом стоявшего ранее на этом месте слова (фрагмент Copy (s,i+length (s2),length (s) -length (s2) -i+1)).

В операции замены первого слова есть небольшое различие – первым сразу становится подстрока замены S3.

Предположим, в строке «Мама мыла раму» нам необходимо заменить слово «раму» на «окно».

Замена производится в одно действие:



В данном случае переменная s2 получит измененную строку «Мама мыла окно». А в случае, если искомая подстрока не будет найдена, переменная S4 вернет в программу исходную строку S.

Но здесь необходимо учесть один момент. В случае, когда в текстовой строке встречается несколько раз одно и то же заменяемое слово, (например, слово «быть» в строке «быть или не быть»), процедуру следует повторить. Поскольку нам неизвестно, сколько раз во фразе может встретиться слово (или символ, или группа символов), один, три раза или 100 раз, мы можем усовершенствовать процедуру для того, чтобы она заменяла их все до тех пор, пока искомой подстроки в строке не останется. Здесь можно применить цикл Repeat с условием выхода.

Видоизменим процедуру InsInString, добавив цикл.


Илл. 22. Усовершенствованная процедура InInstring прекращает заменять подстроку только тогда, когда заменять остается нечего.


Еще одним необходимым элементом нормализации текста является его преобразование из строчного написания в заглавное для удобства последующего оперирования.27

То есть наша строка «Мама мыла раму» после обработки должна выглядеть как «МАМА МЫЛА РАМУ», где все буквы являются прописными, большими.

Приведенная ниже процедура Getups преобразует строку таким образом, что все символы, написанные строчными буквами становятся прописными, а все прочие символы – копирует в той же позиции. Для этого процедура, которая работает со строкой использует другую процедуру, (Getup), которая производит ту же операцию, но на уровне 1 символа.


Илл. 23. Процедуры «поднятия» букв из строчных в прописные GetUps (для строк) и GetUp (для отдельного символа).


Ознакомившись с ними вы можете сделать вывод о принципе их работы. Чтобы не заменять все буквы по одной, процедура GetUp работает с диапазонами кодировок символов, меняя их нужным образом. В данном случае это уже упомянутые диапазоны кодировки DOS: английские строчные буквы от a до z (коды 97—122) и русские строчные буквы от а до я (коды 160—175, 224—239). Определив «попадание» в строчную кодировку мы уже знаем, в какую «сторону» и на какое число следует изменить код, вычесть или прибавить. В частности, для изменения английских строчных символов из кода символа вычитается число 32; а в русских, – до буквы «п» также вычитается 32, с буквы «р» – вычитается 80.


Поскольку процедура Getups изначально готовилась как процедура нормализации, по своему опыту в ней сразу использовались и дополнительные подготовительные элементы как вложенная процедура Deldbspace – удаления двойных и тройных пробелов, а также пробелов, стоящих перед началом и в конце строки:


Илл.24. Процедура «очистки» строки от двойных-тройных пробелов, а также пробелов в начале и в конце строки.


Теперь постараемся подытожить то, что мы получили.

С помощью описанных процедур мы можем нормализовать текст, используя буквально несколько операторов.

Вернемся к нашей проблеме с кодировкой, но теперь будем во всеоружии:


Илл. 25. Обработка ненормализованной строки из кодировки Win, которая содержит лишние пробелы.


Здесь исходная строка написана в кодировке Win и содержит лишние пробелы. Мы перекодируем ее в кодировку DOS, с помощью процедуры Decodetodos, переводим в верхний регистр (и убираем лишние пробелы) с помощью процедуры Getups, и получаем последнее слово строки «раму».


Илл. 26. Нормализация данных привела к требуемому результату, нужному слову в нужном написании.


Следует упомянуть еще о нескольких базовых процедурах работы со строками в Паскале.

Преобразования строк

Str (N, S); – преобразует число N в строку S.

Иногда это требуется для операций над числовыми данными, например, для преобразования даты и времени в наборы символов строкового типа. Дело в том, что в Паскале мы не можем смешивать данные разных типов, и для этого требуется привести их к одному типу.

Для наглядности, рассмотрим процедуру, которая генерирует строку информации о завтрашней дате в читаемом формате. Результат должен выглядеть, допустим, так: «1 марта 2019 года». Все что у нас есть, это информация о дате сегодняшней, полученной посредством оператора GetDate. Эта информация кажется банальной, но в ней мы должны учесть в случае необходимости, содержит ли текущий месяц 30 или 31 день. Также стоит знать, является ли год високосным, если сегодня 28 февраля; стало быть завтрашний день может быть как первым днем календарной весны, так и 29 февраля. Как осуществить этот выбор?

Оператор Str здесь используется дважды в конце: для преобразования числа года и дня и последующей их конкатенации (иначе говоря, объединения) в одной строке.


Илл. 27. Листинг процедуры Gettomorrow, получающей точную завтрашнюю дату в формате строки.


Что происходит? В качестве выходной переменной процедуры мы указали единственную переменную S, в которую будет необходимо отправить результат – строку с датой. Далее, внутренними переменными мы описали Year (год), Month (месяц), Day (день) и Day_of_week (день недели); а также их строковые версии: Years, Months, Days. (Поскольку день недели в данном случае нам не интересен, мы не будем заниматься его описанием и преобразованием).

Первоначально, получив из операционной системы информацию о дате в формате чисел «GetDate (year, month, day, day_of_week)», мы прибавляем к числовому значению дня единицу «Inc (day)», и смотрим, что из этого получится.

В операторе сравнения с перечислением «Case» мы выбираем варианты сценариев. В месяце однозначно не может быть 32 дня, поэтому сталкиваясь с этим числом, мы присваиваем переменной дня единицу и увеличиваем значение месяца на единицу. Но если на дворе был декабрь? Мы помним об этом, и если это так (числовое значение месяца «Month» превратилось в 13), то прибавляем к году единицу «Inc (year)», если сегодня 31 декабря.

Но как мы помним – 31-ый день бывает не в каждом месяце; поэтому мы включаем в исключения и 31-ые числа ноября, сентября, июня и апреля, – если таковые получились, то значение месяца «Month» так же увеличиваем на единицу, а значению дня «Day» присваиваем 1.

Число 30 невозможно даже после крайне редкого дня «29 февраля», поэтому мы предусматриваем и его в виде исключения.

И наконец, 29 февраля бывает не в каждом месяце. Поэтому если мы встречаем такой вариант, нам необходимо уточнить, является ли год високосным или нет.

Точное определение високосного года звучит так:

«Год високосный, если он делится на четыре без остатка, но если он делится на 100 без остатка, это не високосный год. Однако, если он делится без остатка на 400, это високосный год.»

То есть, в данном случае, если мы видим попадание в одно из условий, когда год не делится на 4 без остатка, либо когда делится на 100, но не делится на 400, то считаем этот год обычным и следующим днем считается 1 марта.

Затем мы присваиваем в очередном блоке сравнений case значение месяцев в нужном нам склонении: «января», «февраля» и так далее. И наконец, в результате преобразований числовых данных в строковые, получаем итоговый, нужный результат.


Теперь мы рассмотрим обратную процедуру Val (S, N, R), где происходит преобразование – строки, в N – число, с сообщении об ошибке (или ее отсутствие) в R.

Ниже приведен фрагмент программы в которой число, записанное в строковой переменной S преобразуется в N. Результат операции R при этом сообщит нам, есть ли в преобразовании ошибка (код R <> 0) или ошибка отсутствует (R=0).


Илл. 28. Пример использования процедуры преобразования строки S в число N с результатом преобразования R, с помощью процедуры Val.


Теперь мы рассмотрим процедуру для преобразования фрагмента текста с использованием дополнительной информации. Предположим, мы имеем текст статьи, который необходимо дополнить некоторыми строковыми данными. В статье может встретиться употребление информации о процентах, которое мы должны расширить, например, «95%» заменить на фразу «почти все (95%)». Также при встрече дробного процентного показателя, процедура должна округлить его, например «19,2%» употребить «менее пятой части (19%)». Вариативность такого «очеловечивания» процентных показателей может быть достаточно широкой (в приведенном примере, до 24 вариантов).

Что нам потребуется для упрощения этой задачи. Во-первых, это функция определения символов цифр Trycifra.


Илл. 29. Функция trycifra проверяет символ на принадлежность к цифрам от 0 до 9.


Во-вторых, это уже описанная ранее процедура InsInString. И в-третьих, это файл, «DictPer. txt», который необходимо сохранить в рабочем каталоге программы (по умолчанию это C:/TP/BIN). Он будет содержать числовые диапазоны значений и их описания (кодировка Win). Приведем его содержимое полностью:

«0

3

незначительный процент

3

5

менее двадцатой части

5

8

чуть более двадцатой части

8

10

менее десятой части

10

15

более чем десятая часть

15

16

менее шестой части

16

19

менее пятой части

19

21

пятая часть

21

25

больше пятой части

25

25

четверть

26

27

более чем четверть

27

30

почти третья часть

30

40

более чем третья часть

40

50

менее половины

50

58

более половины

59

65

около двух третей

65

75

почти три четверти

75

77

три четверти

77

80

почти четыре пятых

80

82

четыре пятых

82

92

подавляющее большинство

92

100

почти все

100

100

все

100

10000000

более 100%»

Теперь приступим к сборке и рассмотрим происходящее подробнее.

В процедуре нам потребовалось много строковых переменных для текущих операций (S-S8), две переменные для хранения диапазона (N2 и N3), одна – для текущего показателя (N типа Real), одна – символьного типа (C), одна переменная для связи файла (F типа Text), и две – логического типа (Boolean) для контроля над текущим состоянием операции (b и tryfalse).


Илл.30. Процедура LogicPercent, дополняющая числовые данные процентов различными фразеологизмами.


На вход в процедуру мы имеем строку S, к обработке которой приступаем в случае нахождения в ней символа «%». В цикле меняется значение текущего символа S [i], и если мы встречаем обычные буквы или иные символы, то устанавливаем текущее значение tryfalse=true.

Если же нам встречается число или символы дроби, то мы храним его в переменной S3, поскольку оно может оказаться, а может и не оказаться процентом. Логический указатель числа («нужного» символа) устанавливаем на B=true, и отменяем значение «ненужного» символа TryFalse=false. Также мы дублируем это значение в переменной S8.

Встретив символ процента, цикл завершается. Мы преобразуем значение строковой переменной S3 в число N. Результат преобразования j мы игнорируем, поскольку контролировали код символов и уверены в числовом содержимом переменной. Поэтому используем в дальнейшем j как хранилище для округленного значения N (Round (N)).

Затем мы открываем файл словаря значений DictPer. txt, читаем его по 3 строки сразу, причем первые два «читаем» как числа (N2 и N3) с которыми сравниваем текущее число значения j. Если число j попадает в промежуток между указанными числами, нами используется символьное выражение из файла s6, которое мы не забываем переводить в кодировку DOS (процедура decodetodos).

Теперь протестируем готовую процедуру в следующей программе.


Илл. 31. Программа для тестирования процедуры LogicPercent.


Илл. 32. Пример работы процедуры LogicPercent.


По такому принципу можно обрабатывать большие массивы текста, добиваясь, к примеру, увеличения его уникальности.

26.Вывод управляющих символов на экран равнозначен произведенному действию в блоке текста.
27.К сожалению, предусмотренная для таких операций функция Паскаля Upcase (k) (где k – переменная символьного типа Char) работает практически всегда только с англоязычными символами.

Бесплатный фрагмент закончился.

Бесплатно
220 ₽

Начислим

+7

Покупайте книги и получайте бонусы в Литрес, Читай-городе и Буквоеде.

Участвовать в бонусной программе
Возрастное ограничение:
12+
Дата выхода на Литрес:
21 февраля 2019
Объем:
308 стр. 214 иллюстраций
ISBN:
9785449632814
Правообладатель:
Издательские решения
Формат скачивания:
Текст
Средний рейтинг 4,2 на основе 5 оценок
По подписке
Подкаст
Средний рейтинг 4,8 на основе 4 оценок
Аудио
Средний рейтинг 5 на основе 3 оценок
По подписке
Текст
Средний рейтинг 0 на основе 0 оценок
По подписке
Подкаст
Средний рейтинг 0 на основе 0 оценок
Текст
Средний рейтинг 4 на основе 5 оценок
По подписке
Аудио
Средний рейтинг 4,4 на основе 78 оценок
По подписке
Текст
Средний рейтинг 4,8 на основе 14 оценок
По подписке
Аудио
Средний рейтинг 3,1 на основе 24 оценок
По подписке
Текст
Средний рейтинг 5 на основе 4 оценок
По подписке
Текст
Средний рейтинг 4,2 на основе 5 оценок
По подписке