Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
ему не указали количество символов, удаляет одну из этих трёх частей. А вот
если указано, то... Например в А2: "123456789 абвгдеёжз 123456789 ийклмнопр"
маркер стоит вот в этой позиции: ~~~~~ (попал он сюда: ^13~5)
/3 удалит:
* * *
-/3 удалит:
* * *
+/3 удалит:
* * *
Сразу и заранее предупреждаю: форматное выражение оператора Write это
всегда одно "слово": как только встретился конец оператора, например точка с
запятой, или запятая, разделяющая его части, или даже просто пробел — значит
форматное выражение кончилось. (Эти символы могут быть там только в составе
текстовых констант. То есть в кавычках.)
Поэтому в роли пробела там символ '_' (подчеркивание) — пустая операция,
которая ничего не делает, за-то всегда успешно.
И сильно забегая вперёд: у нас там есть еще одна пустая операция '' (обратная косая черта), которая тоже ничего не делает, но всегда неуспешно. В результате чего выполнение форматного выражения сразу же и заканчивается, как впрочем и по любой ошибке. (Например велели передвинуть маркер на десять символов, а их до конца строки только семь...)
Вернее, дело обстоит так: чтобы немедленно прекратить выполнение форматного выражения есть операция '!', которая еще и вывод текущей строки запрещает. (А если надо всё наоборот: строку вывести, а выполнение форматного выражения продолжить — есть операци '.' (точка).) А для того, чтобы в зависимости от успешности/неуспешности выполнения очередной операции поступить по-разному — есть "постфиксы" '&' '' '?'. Например в: 'x&y' 'xz' 'x?yz' операция y выполняется если x выполнилась успешно, а операция z — если нет. Но во всех случаях обработка строки после этого продолжается. А вот если её таки надо завершить, то: 'х&'. (Другие варианты тоже грамматически правильны, но смысла не имеют: 'x\' это то же самое, что просто 'x'; 'x?y' то же самое что просто 'xy'; а 'x?z' делает то же что и 'х&'.
Но это мы таки сильно забежали вперёд... Вернёмся к нашим баранам.
Вот например надо во всех копируемых строчках заменить "Вася" на "Петя".
Запросто: Write %"Вася"*"Петя" (изначально '+' был необязателен)
W %^+"Вася"*"Петя" (^ чтобы точно с начала строки)
— Ага, один раз. А если слов "Вася" в строке несколько?
— Нам нужен префикс повторения!
Ага.
— Но префиксы обычно действуют только на одну, следующую за ними операцию.
А у нас их здесь две: найти и заменить.
— Значит еще нужны скобки, группирующие несколько операций в одну.
Вот где-то так: Write %@(+"Вася"*"Петя")
Замечательно.
— А когда этот наш цикл кончится?
— Когда +"Вася" больше ничего не найдёт.
Ага.
Отсюда идея, что если очередная операция выполнилась неуспешно, то на
этом — всё: выполнение форматного выражения прекращается. (Ага: это для текущей
строки прекращается. Write сбрасывает её в канал вывода, берёт следующую из
канала ввода и всё по-новой...)
— А если всётаки надо продолжить?
— На этот случай введём "постфиксы" '&' и '' которые берут этот самый статус
успешности/неуспешности предыдущей операции и либо выполняют либо пропускают
следующую. То есть '&' если да, а '' если нет. А еще универсальный '?' сразу
для обоих случаев.
(Сначала я его было сделал как скобки — по аналогии с условным выражением
? : языка Си, задействовав в качестве закрывающей скобки символ '|', но потом
таки одумался: просто две следующие операции, а скобки у нас и так уже есть.)
Кстати о птичках, то есть о скобках: префиксы + и — (в отличии от @)
действуют на операции только "персонально". Поэтому +(...) не даст никакого
эффекта: префиксу действовать не на кого. И он выполнит свою исходную миссию:
сдвиг маркера на одну позицию.
Ах, да: уж коли у нас маркер приобрёл размер, то надо бы и его научиться
устанавливать: ~45 (вот — в 45 символов). А так же ~$ и ~^ — от текущего места
до конца и до начала строки. (А еще ~. — до "метки", но про метку — потом...)
А кроме этого операция вставки устанавливает маркер по размеру
вставленного, поиска — по размеру найденного, а вот перемещение и удаление его
размер обнуляют.
В том числе и сдвиг на 0 позиций. Но просто 0 или -0 оставляют маркер там,
где он был (только размер у него теперь будет нулевой, как и после любого
перемещения), а вот +0 таки его сдвигает — на размер самого маркера.
А что это мы всё без молока да без молока? В смысле — исключительно с
константами? У нас здесь язык программирования, или я где?! У нас же
переменных полно — пусть пользу приносят! (Чем мы хуже кота Матроскина?)
В общем текущее положение маркера... А вернее размер любой из трёх частей,
на которые он делит строку в А2, сохраняем в переменной следующим образом: =Х
+=Х и -=Х чтобы потом применить (вместо числовой константы) как #Х (где Х -
одна буковка). И пусть в миру (то есть в самом Фокале) и имя у этой переменной
будет такое-же: #Х. Мы еще не забыли, что всякие # $ & |... там тоже считаются
буквами, и такое имя — вполне допустимо?
Получились еще две операции: '=' и '#' — "сохранить" и "применить",
нуждающиеся в уточнении, где именно сохранять (и что потом применять). В том
числе текущее положение маркера в некотором тихом месте: =. чтобы потом
обменять их с маркером местами: #. т.е. это вот та самая, уже упоминавшаяся
"метка". Штука, кстати, весьма удобная...
Вот, значит, какая задача: копируем строки с помощью оператора Write %...
и если в строке есть символ : (двоеточие), то само это двоеточие удалить, а
текст перед ним перенести в конец строки и "отгородить" от её содержимого
символом ; (точка с запятой). (Это мы ассемблерную программу покалечить хотим:
превратить все метки в комментарии.)
— Ага, разбежались! Надо где-то сохранять вот этот переносимый фрагмент
строки. (А то придётся таскать по одному символу...)
Поэтому по аналогии с переменными для чисел, введём "регистры" для таких
вот текстовых фрагментов. И обозначим их цифрами 0..9, а в остальном — всё то
же самое. И сразу договоримся: что если пишем фрагмент в седьмой регистр =7 то
в переменную #7 пусть автоматически записывается его размер. Вот теперь:
Write %+":"/-=1-/$*';'+*#1
Непонятно? А навставляем _ (аналог пробела), пронумеруем и прокомментируем:
Write %___+":"___/___-=1___-/___$___*';'___+*#1
0 1 2 3 4 5 6 7
0. думаем, что изначально маркер стоит в начале строки (так оно и есть)
1. ищем символ "двоеточие" (если не найдём, то на этом всё и кончится)
2. удаляем найденное
3. сохраняем в регистре 1 всё, что перед маркером (было перед двоеточием)
4. всё что перед маркером — удаляем
5. ставим маркер в конец строки
6. вставляем туда точку с запятой
7. после того что под маркером (а там только что вставленная ';') вставляем
фрагмент, ранее сохраненный в регистре 1
Пробуем.
Фокус не получился — факир был пьян! Нет, с терминала-то всё нормально,
а вот из файла... Там оказывается в конце каждой строки символ перехода на
следующую. (Даже два: перевод строки и возврат каретки.) Вот после них мы
этот текст и пристроили! А редактор командной строки, с помощью которого мы
набираем строчки на терминале, оказывается таковых не вставляет. Надо бы не
конец строки искать, а вот их...
Забегая вперёд, скажу, что это будет выглядеть: +{!}
Write %___+":"___/___-=1___-/___+{!}___*';'___+*#1
1 2 3 4 5а 6 7
Пробуем. (Но сейчас уже только с файлом)
Опять не слава богу! Нет, всё сработало, кроме последней строки, где
оказывается нету перехода на следующую. Вот там +{!} ничего не нашла и
соответственно операции 6 и 7 уже не выполнились.
Ладно, пишем так:
Write %___+":"___/___-=1___-/___$___-{!}____-*';'___+*#1
1 2 3 4 5 5б 6 7
Здесь: 5 — ставит маркер в конец строки и 5б — ищет этот самый переход на
следующую, но от конца к началу, а если не нашла, то конструкция _ (не
делающая ничего содержательного) просто не даст прекратить выполнение.
Ну вот сейчас наконец-то всё отработало правильно...
Выражения: {...}
{!} — это вот как раз было оно, причем экзотического "текстового" типа...
Для универсальности одних переменных недостаточно! Тем более, что в нашем
распоряжении вся хилая мощь КАЛькулятора ФОрмул! Но фокаловское выражение
"изолируем" от форматного с помощью фигурных скобочек. И используем как
числовой параметр целую часть его значения. В {...} кроме выражения (которое
там должно быть только одно) могут быть символы _ (подчеркивание) в роли
пробела и конструкции =Х ("присваивание", где Х — буква) чтобы при
необходимости сохранять вычисленное в переменных.
Разумеется, в таком выражении ничто не мешает использовать функцию FSBr,
которая вообще-то обращение к подпрограмме. И таким образом для каждой
очередной строчки выполнять любой код... Но даже если она вернёт ноль — размер
маркера таки попортит... (Впрочем, дело поправимое: =Х{fsbr(....)}~#X)
Выражение текстового типа устроено в точности так же, но отличается тем,
что начинается с чего-то однозначно текстового, результатом имеет строку, а
в присваивании =N должна быть цифра, указывающая номер регистра чтобы её
сохранить. Единственная операция — сцепление элементов ("конкатенация")
специально никак не обозначается. А числовые значения, которые там тоже могут
присутствовать, обозначают коды символов.
Ради них по большому счету это и затеяно: ну нету в Фокале концепции
"экранирующего символа". Как например в Си (и вообще в UNIX`е), где это
(обратная косая черта), позволяющая в "..." изобразить как служебные символы,
включая самоё себя и огораживающие эту константу кавычки, так и коды,
графических обозначений просто не имеющие. (И потому известные как "слепые".)
Так уж исторически сложилось, что коды символов в Фокале сами по себе: с
ними работала исключительно функция FCHR, а текстовые константы тоже сами по
себе — исключительно для общения программы с пользователем. И вместе сошлись
они вот только сейчас. Вот и.
Еще в текстовом выражении кроме констант вида "..." и кодов символов,
включая обозначающий конец строки восклицательный знак, могут быть конструкции
#N и :NNN, где N — номер регистра, а NNN — номер программной строки.
(N — одна цифра, а NNN — выражение общего вида).
Конструкция {...} понравилась и тут же нашлось множество желающих её
использовать: @{...} #{...} ={...} %{...}
Префикс повторения конечно же самый первый! (Куда уж без него...) Нет,
если всего лишь надо указать количество повторений — нет проблем. Например:
@12+*'*' вставит ровно двенадцать звёздочек. (+* а не просто * потому, что
оно не вставить, а заменить норовит — то, что под маркером. А под маркером то,
что вставлено в прошлый раз, т.е. предыдущая звёздочка.)
А вот полноценный заголовок, с переменной-счетчиком, начальным, конечным
значением и шагом — всё как в операторе For i=0,44,2;.... — @{0,44,2=i}....
— Ага-ага! А как же запятые?! Их же в форматном выражении — низзя...
— Так ведь в фигурных скобочках. Там в выражении и они и в обращении к функции
могут быть и между индексами... Ну ладно, поелику это и в самом деле вроде как
нарушение принципов, от сего момента заменим все запятые на '|' хотя пока
(временно!) разрешим оба варианта. Тогда аналог For i=0,44,2;.. — @{0|44|2=i}..
— н-да, а с запятыми-то лучше смотрится... Привычнее...
И к тому же символ | это ведь буква? Ну да — не цифра и не разделитель.
И назначать её разделителем только вот ради этого случая... В общем нехорошо
получилось! Вернём-ка мы всё это в зад. Но попозже...
Заголовок цикла может быть и в виде текстовой константы. Он сопоставляется
с фрагментом строки начиная с текущего положения маркера. И отличается
возможностью дополнительно содержать ^ и $ указывающих начало и конец строки.
Если учесть, что конструкция из заголовка цикла и постфикса (без "тела
цикла") — суть условное выражение, где заголовок цикла отрабатывает ровно один
раз, проверяя условие. То это получился некий сурогат шаблона. Которых тогда
еще небыло. К тому же строчное значение, не будучи чьим-то правым операндом,
даже без + (как сейчас) так и норовило пройтись по всей строке...
Конструкция %{...} это обращение к одной из программных строк, номер
которой указан выражением в скобках. Выражение — только числовое. (Хотя по
аналогии с :номер_строки в строчном выражении и может начинаться с двоеточия.)
Смысла в текстовом выражении в данном случае нет ровно никакого: к подпрограмме
в регистре N обращаемся: %N, а модная нынче "лямбда" (где она есть), дающая
анонимную подпрограмму, нужна вовсе не для того, чтобы эту подпрограмму сразу
же и выполнить (что нам мешает сделать эти действия просто так?), а чтобы
заховать куда-то на черный день, или передать кому-то в виде параметра...
Как и любой уважающей себя подпрограмме, этим тоже полагаются параметры.
Хотя бы один. В качестве которого — следующая после %N или %{...} конструкция.
Она не выполняется и доступна в "подпрограмме" как текстовый фрагмент (без
ограничивающих её скобочек или кавычек, если конструкция составная) с помощью
#%. Хотя можно и выполнить: %%.
Обратим внимание: кроме %{...} и %N может быть еще и %Х (где Х — буква).
— Ну и чем же это %Х отличается от просто Х?
— А вот этой самой возможностью получения следующего за ним параметра.
Вообще-то сложилось забавное положение: всё наше форматное выражение
задумано как Write %Буква; — каковая буква укажет одно из встроенных
преобразований, которых до сих пор... (Вот именно!)
А Write %_какие_то_операции_; — это чисто от бедности. Однако, если среди
них эта самая Буква таки встретится... То должна отработать то, что ей
поручено — применительно к тому фрагменту строки в А2, который в этот момент
под маркером. Для чего сделано так, чтобы в самом начале — когда строчка
только-только прочитана, маркер стоял в её начале и включал её всю.
Но теперь вдруг появилось два варианта: просто Буква и %Буква, отличающийся
вот как раз наличием параметра... Которого, как оказалось, нам так не хватало!
Дело в том, что предполагалось, что все эти встроенные преобразования будут
перекодировками — чтобы просматривать тексты, записанные не одной только 866-й
(ДОС`овской)... А вот захотим мы преобразовать из одной кодировки в другую...
Можно конечно и в два этапа — сначала в текущую ДОС`овскую, а потом из неё. Но
честно говоря, это не есть хорошо: в ДОС`овской может например не быть
некоторых символов, которые есть в этих двух — в обоих. А тут пожалуйста: %Xy.
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |