Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
"ШАБЛОН", он же "регулярное выражение" (конструкция <...>) — это только один
из элементов форматного выражения, но тем не менее отдельный язык. Впрочем,
несложный — чуть расширенный вариант шаблонов UNIX`овского sh. Отличающийся
тем, что '?' и '*' не сами обозначают один любой символ и произвольное их
количество, а наделяют таким свойством следующий после них элемент. И потому
называются "префиксами повторения". Ну и еще тем, что [...] и <...> могут
вкладываться друг в дружку как матрешки, и, соответственно, элементами
перечисления [...] могут быть не только отдельные символы, но и более сложные
конструкции. Ну и "встроенные" шаблоны конешно, типа %Буква...
Шаблон может быть "анализирующий" и "генерирующий". Анализирующий
сопоставляется с фрагментом строки (например когда с его помощью производится
операция поиска), а "генерирующий" сам формирует фрагмент строки по образчику
того, с чем ранее сопоставился анализирующий. В этом качестве он выступает
когда служит правым операндом операции вставки '*'. Удачно сопоставившийся
анализирующий шаблон оставляет после себя "протокол", который генерирующий и
использует...
Грамматически, шаблон это аналог строчной константы. Отличается от неё
тем, что в нём нe все символы изображают сами себя, некоторые имеют
специальный смысл. В принципе таковыми можно считать все "значки", вне
зависимости от того, задействованы они в настоящий момент или нет.
Главный спецсимвол '%' — "экранирующий": он делает другие спецсимволы
(включая самоё себя) — обычными, и некоторые обычные — специальными.
Следующие по важности это префиксы повторения. Они предписывают повторить
следующий за ними элемент шаблона:
'*' — ноль или более раз
'+' — один или более раз
'?' — ноль или один раз
{N} — ровно N раз
{N,M} — не менее чем N и не более чем M раз, где N и M — числа или
фокаловские выражения, или пропущены и тогда для N — ноль, а для M — скока хошь
'-' — сразу после префикса повторения (перед повторяемым элементом)
предписывает применять не "жадный" алгоритм, пытающийся захватить сразу как
можно больше символов, а "ленивый" — действующий противоположным образом.
Таким элементом может быть:
— любой "обычный" символ (или '%' плюс специальный) — изображает сам себя
(но если это буква то с учетом предшествующего шаблону "х" или "Х")
— конструкция '%' плюс буква — встроенный шаблон (см. далее)
— символ '^' или '$' — сопоставляются с началом и концом строки
— символ '!' — сопоставляется с разделяющими строки символами ПС/ВК,
они же 'n' и 'r' с кодами 10 и 13.
— символ '.' — сопоставляется с любым символом
— символ '_' ничего не делает, но это тоже элемент шаблона
— конструкция <...> — сопоставляется если сопоставились все её элементы
— конструкция [...] — сопоставляется если сопоставился один из её элементов
Угловые <...> и квадратные [...] скобки ("последовательность" и
"перечисление") могут вкладываться друг в дружку на любую грубину. Круглые
скобки (...) пока никак не используются (оставлены про запас) но тоже
отслеживаются — т.е. их баланс тоже должен соблюдаться, так же как и для
скобок других видов. Кавычки пока никак не задействованы: <...> тоже своего
рода кавычки, отменяющие специальный смысл кавычек другого типа.
Внутри "перечисления" [...] префиксы повторения не имеют смысла, символы
'*' '?' '+' — обычные. Конструкция {N} изображает один символ с кодом N.
Но за то как и в UNIX`е есть "диапазон", например конструкция А-Я обозначает
все заглавные русские буквы. Вернее все символы, коды которых находятся в
промежутке между кодами двух указанных. Так что в данном случае, увы, без
буквы Ё, которая в используемой ДОС`овской кодировке — отдельно. (А диапазон
маленьких русских букв здесь вообще разрывный! Его пришлось бы обозначать как
[а-пр-я] или даже [а-еёж-пр-я].)
Кроме того "перечисление" может быть "негативным": [~...] — сопоставление
с ним считается "удачным" если не сопоставился ни один из его элементов.
* * *
Встроенные шаблоны вида %Буква сопоставляются с символами, принадлежащими
к некоторой группе:
%B %b %Б %б — любая буква, в т.ч. %Б и %б отдельно заглавная и строчная
%L %l %Л %л — любая латинская -//-
%R %r %Р %р — любая русская -//— в текущей кодировке
%D %W %K %I — русские буквы в кодировках ДОС, Win, КОИ-8, ИСО
%У %у %U %u — уникод, здесь по-другому:
%U — любой правильный символ в utf-8
%u — один единственный "неразрывный пробел нулевой ширины" с кодом 00FEFF
но в любой из разновидностей уникода: по нему собственно эти
разновидности и различаются. Если сопоставился — устанавливает
внутренний признак типа уникода
%У %у — только русские буквы, и пока только в utf-8
а так же
%Ц %ц %C %c — любая цифра
%Г %г %G %g — любой символ псевдографики
%П %п %P %p — пробел и "слепые" символы с кодом меньше чем у пробела
но
%С %с %S %s — текстовая константа вида "..."
а прошлый раз было, но пока еще не восстановлено:
%Ч — число общего вида
%Э — правильное фокаловское выражение
%Ш — правильное форматное выражение оператора W, включая шаблон
(Подробнее — см. в справке к Фокалу выдаваемой оператором Help.)
* * *
Анализирующий шаблон по мере сопоставления с фрагментом строки формирует
"протокол", по которому генерирующий шаблон мог бы соорудить свой фрагмент.
Но который, возможно, может быть интересен и сам по себе: этот протокол
фактически развёртка в линейную последовательность дерева разбора шаблоном
фрагмента строки.
Поэтому принято (временное) решение вставлять в А2 текущий (последний по
времени) протокол сопоставления шаблона операцией * с аргументом *. (Т.е.
протокол можно только вставить, использовать так же как и другие строчные
значения — нет.)
Организован протокол следующим образом:
— "последовательность" <...> (в том числе и весь шаблон целиком) фиксируется в
в протоколе в виде пары скобок '<' '>', между которыми — её элементы
— любой префикс повторения "выгораживает" участок внутри последовательности,
начало которого отмечается символом '*' а конец — '|', и между ними — элементы,
с которыми сопоставилась повторяемая им конструкция. В том числе возможно что
и ни одного.
— "перечисление" [...] отображается парой скобок '[' ']', в которых
число (номер сопоставившегося элемента), запятая и то, что с ним сопоставилось.
— элемент шаблона, успешно сопоставившийся с нулём символов отображается '_'.
Это и негативное перечисление [~...] у которого не сопоставился ни один из его
элементов, и пустой шаблон '_', и '^' '$' сопоставляющиеся с началом и концом
строки
— элемент шаблона, сопоставившийся с одиночным символом 'Х' отображается в
протоколе как '.Х' — это может быть и символ, изображающий сам себя и '.'
(точка) обозначающая любой символ
— встроенный шаблон вида %Б сопоставившийся с одиночным символом 'Х'
отображается в протоколе как 'БХ'
А вот встроенных шаблонов, способных сопоставится с чем-то более сложным, у
нас пока только два: %U — сопоставляющийся с символом уникода — отображается в
протоколе как Uчисло, и %S сопоставляющийся со строчной константой в кавычках и
отображающийся в протоколе как S"..."
Что делать в более общем случае — еще надо подумать...
* * *
Генерирующий шаблон (теоретически) должен быть конгруэнтен анализирующему.
Тогда каждому его элементу достанется элемент протокола, записанный
аналогичным элементом анализирующего, которым он бы смог руководствоваться.
Например [...] вставит элемент с тем же номером, каковой отработал в [...]
анализирующего шаблона, '*' повторит свой элемент столько же раз, сколько и
аналогичная конструкция в анализирующем, '.' вставит то, что ей досталось как
есть, а %Б с соответствующим преобразованием (например превратит доставшуюся
букву в заглавную).
А чтобы количество элементов можно было сделать строго одинаковым, у нас и
есть пустой шаблон '_' (подчеркивание), не делающий вроде бы ничего, но элемент
протокола вставляющий и соответственно потребляющий.
Ага-ага: должен да не обязан! Очень даже запросто так может быть, что не...
Поэтому будем считать, что генерирующий шаблон сопоставляется с протоколом, а
генерируемый им текст — всего лишь побочный эффект. Ясный пень, что когда
шаблоны конгруэнтны, сопоставление будет один в один. А вот если нет, если
элементу шаблона сопоставляется чужой элемент протокола... На этот случай
разделим все элементы шаблона на "одиночные" и "множественные" — по тому,
сколько элементов протокола они бы хотели заполучить в своё распоряжение.
Множественные это <...> и *Х, а все остальные — одиночные, включая [...].
(Под * имеются в виду любой префикс повторения, а Х — повторяемый им элемент.)
Соответственно, "множественные" элементы протокола это <...> и *...| но первый
"главнее": второй только "выгораживает" себе его кусочек.
Настоящим предполагаем, что:
* множественный элемент генерирующего шаблона может "освоить" любой
доставшийся ему множественный элемент протокола, а вот с одиночными пусть
поступают по-разному:
— конструкция <...> пусть скромно предоставляет один и тот же элемент
протокола каждому своему элементу
— а конструкция *Х пусть нагло пытается захватить все доступные элементы
протокола вплоть до ближайшей закрывающей скобки '>'. Но при этом должна
"поделиться" с аналогичными конструкциями, если они есть.
* одиночные элементы...
— элементы, изображающие сами себя (обычные символы и экранированные с
помощью % спецсимволы) никак не используют доставшийся им элемент протокола.
— элементарный шаблон . (точка) вставляет это один в один, как есть. При
чем не только одиночный символ, но и любую скольк угодно сложную конструкцию.
— элементарный групповой шаблон типа %Б действует так же как . (точка) для
всех символов, кроме букв, которые преобразует к указанному им типу алфавита.
(А на счет не-элементарных встроенных шаблонов еще надо подумать.)
— элементарные шаблоны _ $ ^ не порождают никакого текста.
— конструкция [...] если ей попался такой же элемент протокола, отрабатывает
указанный ею свой элемент. А если нет — самый первый.
* * *
Ну вот, вроде как всё придумал и даже почти сделал... Так, вроде бы только
кое-какие шероховатости остались. Типа что в конструкции {N,M} шаблона тоже бы
неплохо разрешить присваивание результата фокаловским переменным. Или вот, как
и для всего форматного выражения, надо бы и в шаблоне сделать %N аналогом
обращения к подпрограмме...
Ан вдруг приходит в голову мысль: а простейшие вещи, типа сравнения двух
строк на полное совпадение с помощью этого замудренного механизма — как?
Оказывается, у нас нету бинарных операций со строками — все унарные.
Нет, вставить одну строку внутрь другой, или найти совпадающий с ней фрагмент,
это пожалуйста. (Помести её заране в регистр, и...) Даже на полное совпадение
особого труда не составляет. В том числе, по желанию, игнорируя или нет
различия между разными видами буковок. (Если регистр например седьмой, то не
#7 или {:7}, а {:7$}, чтобы и конец строки захватить. А дальше — постфикс
какой ни будь...)
А вот сравнить две строки в рассуждении алфавитного порядка их следования
(типа: какая "больше", то есть позже по алфавиту?), или найти наибольшую общую
подстроку — то, что для третьего Фокал задумано как "полукорреляция" (на
предмет вот так доопределить для строк операцию ^)...
// Но тут наступило утро и Шахеризада завершила дозволенные речи //
================
* * *
===============
// а всё что дальше — рассуждалка типа "как бы нам обустроить..." //
// так что далее читать не следует, а то такого можно начитаться...! //
Как показала практика, все такие описания пишутся для того, чтобы
"с разбегу" преодолеть некий логический барьер. Прошлый раз это были вот те
самые генерирующие шаблоны, а сейчас — как бы организовать доступ к
структурированным данным. Таким, как например поля заголовка пакета им.тов.
Залётова, или записи реляционной базы данных из файла типа *.dbf
Структура — это вам не строчка: она — набор полей, в каждом из которых — по
такой вот строчке... Или по числу. Или исчо что — ну вот ссылка например...
На что-то...
Ага-ага: для чисел у нас аккумулятор А1, для строчек А2, а для ссылок
выходит что А3, так? С А1, а вернее с числами работает весь базовый Фокал,
с А2 тоже вроде как научились, а теперь очередь А3 подходит...
Поэтому мысль номер один — считать тип очередного поля в некую переменную,
а значение в это время нехай сразу окажется в одном из аккумуляторов. Только
вот синтаксически это оформить — как?...
Ну например Ask :имя_поля: = Т; или даже Ask :имя_поля: = Т, Р, П...
Где Т — тип поля: 0 — число, 1, строка, -1 — ссылка
Р — размер (для строки) и какие ни будь признаки для остальных типов.
В том числе -1 если ссылка — "нулевая", никуда не указывает. Иначе, например,
размер потока (файла), или записи, на которые ссылка. Следующие переменные,
если есть — еще какие либо параметры. (Порядковый номер поля, его смещение от
начала записи, набор неких аттрибутов...) Но '=' только при двойной
буферизации, иначе ошибка.
Тащить '=' в оператор Ask, где его раньше никогда небыло, конешно не есть
хорошо, но без этого может быть нежданчик. Если при переходе к следующему
полю тупо тащить его содержимое в А2, а в А1 например его тип, как я хотел
раньше, то как это отличить от просто перехода к следующему табулостопу,
никак не изменяющему содержимое аккумулятора? (Даже если первое исключительно
для файлов с двойной буферизацией, а второе — без таковой. И смешивать их не
предполагается.)
* * *
ПРО ЗАПИСИ И ПОЛЯ ОНЫХ
Итак, запись делится на поля, в каждом из которых — ровно по одному
значению. А вот каковы типы этих значений, привязан ли тип к данному полю,
или может меняться по нашему произволу — в зависимости от того, какое
значение мы в это поле запишем; фиксирован ли и при этом упорядочен ли каким
то образом сам набор полей, или тоже — предмет нашего произвола — пусть всё
это пока остаётся за кадром. Потому что в одних случаях так, а в других эдак.
В каком ни будь Питоне или Луа, интерпретируемых языках с полиморфизмом,
тоесть возможностью писать в переменную значение абсолютно любого, какого
только вздумается типа (разумеется из тех, которые есть) — потому что код
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |