Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование для начинающих #20


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

Программирование для начинающих

Выпуск 20

11 JUN 2001

 
 
 
Ведущий рассылки: Вячеслав Мацнев
e-mail: stac@stacmv.net
Bonan tagon, geamikoj! Что значит, доброго Вам дня, друзья!

В этом выпуске читайте:

ОТСЕБЯТИНА

Как обычно, начинаю свое нытье.

Вот, уже лето. А это значит сессия и каникулы. А что значит это, вы уже знаете по опыту прошлого года.

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

Армия. Что ж, посмотрим, чем сегодня детей пугают.

Посмотрим, но, возможно, не увидим.

Это я вам говорю, чтобы не удивлялись моему внезапному исчезновению.

А... Продолжаем разговор.

В прошлом выпуске, когда рассказывал про кодирование символов, я упомянул про рисунки сайте. Сейчас они должны уже быть там. Вот прямая ссылка: http://stacmv.nm.ru/lib_files_picsfori19.html

Чтобы все было еще хуже, чем есть на самом деле, рисунки сделаны большими и плохого качества. Поэтому тем, у кого плохая связь, лучше заказать их (если уж так надо) на email, например, через WWW4Mail, русский хелп к которой опять появился на сайте. Или вообще забудьте про эти рисунки

Впрочем, можно посмотреть и уменьшенные копии картинок. Они достаточно большие, чтобы увидеть все, что надо. И занимают где-то 195Кб (все вместе). Указанная выше страница их, как раз и загружает.

Еще, порывшись в своих старых компактах, я нашел довольно интересный файл: langlist.zip. В нем находится текст, который называется:

The Language List - Version 1.9, January 13, 1993

Collected information on about 2000 computer languages, past and present.

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

Список Языков - Версия 1.9, Январь 13, 1993

Сводная информация о примерно 2000 компьютерных языках прошлого и настоящего.

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

Я хотел поместить этот список на страницах сайта, но меня остановил размер файла: 381Кб текста или 435Кб HTML.

В zip'е это 186Кб, что уже не так плохо. Желающие могут скачать. Прибавьте имя файла к адресу сайта. Если ничего не получится, то попробуйте в другой раз.

Да, скачать что-нибудь с сайта иногда не получается. Во-первых, некоторых файлов там нет (таких, как msdos.sys и других). Во-вторых, иногда слишком много пользователей обращаются к сайту NewMail.ru, моему хостинг-провайдеру и он, бывает, не справляется.

Но не переживайте, вот приеду, сделаю пару-тройку зеркал.

БЕЙСИК .::. Работа со строками

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

Что такое символьная информация? Это отдельные символы, наборы символов или строки и наборы строк. Символы это, как привычные нам буквы и цифры, так и управляющие символы (вспоминайте прошлый выпуск).

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

Начнем с ввода, тем более, что эта тема вам во многом уже знакома.

Ввод информации

Рассматривать будем ввод с клавиатуры.

Вы уже знаете два основных средства Бейсика для ввода символов (INKEY$) и целых строк (INPUT).

Формально, INKEY$ тоже осуществляет ввод строки, т.к. в Бейсике есть строковой тип и нет символьного. В Си, например, символ и строка из одного символа это очень даже разные вещи. И не только в Си, впрочем.

Здесь требуется пояснение. Символ, как мы выяснили в прошлый раз, в памяти компьютера представляет собой ASCII код, т.е. восьмиразрядное число и занимает один байт.

Строка из одного символа, в общем случае, занимает больше место. В Си, например, 2 байта (собственно символ + признак конца строки).

В Бейсике есть два типа строковых переменных: переменной и постоянной длины. Длина первых определяется длинами присвоенных им констант. Длина вторых жестко задана при объявлении переменной и не может быть изменена в процессе выполнения программы.

DIM String1 AS STRING     'стринг переменной длины
DIM String2 AS STRING*40  'стринг постоянной длины (40 символов)

Из примера видно, чем отличаются определения разных типов строковых переменных.

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

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

Но вернемся к нашим баранам.

Оператор INPUT служит для ввода значений переменных с клавиатуры. Он прекрасно Вам знаком, в том числе и по домашним заданиям.

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

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

Всегда, даже когда нужно ввести число, используйте строковые переменные.

Почему? Потому что, пользователь по своей природе человек деревянный (но никогда не говорите об этом ему) и любит жать часто не те кнопки, какие требуется. А иногда и непонятно, какие кнопки нужно нажимать.

Так, представьте себе программу управления реактором.

INPUT "Введите требуемую температуру активной зоны блока J:",TJ%

Вы видите, что я вопреки доводам разума и своим собственным словам применил переменную целого типа (INTEGER).

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

Подразумевается, что значение температуры должно быть указано в Кельвинах, т.е. не может быть отрицательной. Проверку положительности легко сделать с помощью: IF TJ%>0 THEN все нормально, парень пока не свихнулся.

Справка:
--------

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

Единица измерения, в честь автора называется Кельвин или К.

Шкала температур Кельвина имеет только неотрицательные значения. Температура 0К (ноль Кельвинов) это пресловутый абсолютный нуль, при котором прекращается всякое движение молекул. Считается, что эта температура не достижима. Даже температура глубокого вакуума в расчетах принимается равной 4К.

Относительно шкалы температур Цельсия шкала Кельвина сдвинута влево на 273 градуса. Т.е. 0К=-273 град. Цельсия, а 273К=0 град. Цельсия.

Конечно, мы будем сверять TJ% не с нулем, а с какими-то реально достижимыми минимальным и максимальным значениями.

Ну а если дежурный случайно нажмет ENTER, не успев ввести число?

Как вы помните, неопределенным переменным по умолчанию присваивается значение 0. Т.е. возникнет такая же ситуация, как и при вводе нуля. В данном примере это не важно, т.к. ноль не допустим. А в другой ситуации, где можно вводить ноль, как отличить его от ошибочного нажатия ENTER'а? Правильно, никак.

Представьте теперь, что у парня поехала крыша (это иногда бывает с пользователями реакторов), и он вместо значения температуры вводит фразу: "Что ты имеешь в виду?". Хотел сказать это по рации, но заработался и напечатал на клавиатуре.

Теперь все зависит от компилятора. Раньше ввод строковой информации на запрос числа просто игнорировался, т.е. переменной присваивался ноль. Последние компиляторы просто повторяют запрос. Правда делают они это очень оригинальным способом, о котором программист может даже не знать. Но это не про вас, потому что я вам про это, как раз, сейчас рассказываю.

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

И тут, под влиянием человеческого фактора, происходит следующее (напоминаю, оператор вместо числа ввел строку). Внимание.

От предыдущего ввода отступается две строки. Печатается фраза "Ввод с начала" и повторяется приглашение на ввод числа.

А теперь самое интересно (даже более интересное, чем "испорченный" экран). Оператор человек умный, но он не может понять: "Как сначала? С самого начала?" (до этого он ввел температуру блоков, A,B,C,D-I). Хорошо если в запросе сказано какую температуру вводить, но обычно текст запроса печатается с помощью PRINT в строго определенном месте экрана и INPUT'ом не повторяется.

Итак, что изменится, если в INPUT будет стоять строковая переменная.

Не будет проблем описанных выше. Можно будет отличить ноль от ошибочного или намеренного нажатия ENTER'а, потому что в последнем случае переменной будет присвоено значение пустая строка "". Плюс, можно предотвратить ввод всякой абракадабры, обработав ошибку самостоятельно.

Не слишком много преимуществ, скажете Вы. Подождите, вот начнете серьезные программы писать...

Остался лишь один вопрос. Ввели мы строку, как преобразовать ее в число, ведь, строки не могут использоваться в расчетах?

Для этого нужно воспользоваться функцией VAL() (от VALue - значение). В качестве параметра эта функцию принимает строку (символьную запись числа), а возвращает само число. Преобразование строки в число идет до конца строки или до первого нечислового символа. Причем "минус" допустим только в начале, десятичная точка только единожды.

Примеры:

VAL("123")=123
VAL("12d34")=12
VAL("sd4")=0

Ехидный читатель может заметить, что VAL("")=0 и, мол, как теперь отличить 0 от случайного нажатия ENTER'а. Ухмыльнувшись, я отвечу, что проверку на ошибочное нажатие ENTER'а нужно делать перед преобразованием строки в число.

А, для обратного преобразования существует функция STR$(), которая число преобразует в его символьную запись.

Кстати, в Паскале нет такой функции. Там есть такая процедура. Мне жаль Паскалистов и себя (когда я на нем пишу и применяю процедуру str). Ну, вы понимаете. К счастью написать свою функцию не сложно, что я обычно и делаю (всегда, когда встроенные средства доставляют неудобства).

Ок. С инпутом все. На очереди инкей.

INKEY$ вы тоже знаете не понаслышке. Это практически единственный способ ввести символ (без необходимости нажатия пользователем ENTER'а), ну и просто уловить нажатую клавишу, чтобы потом совершить процесс управления. Например, курсором.

Курсорные стрелки относятся к клавишам, не имеющим ASCII кода. Вспоминайте снова прошлый урок.

Любая функция DOS, осуществляющая ввод символа с клавиатуры, а фактически читающая его из буфера, возвращает ASCII код символа или нулевой код.

А вы, конечно, думали, что информация из прошлого выпуска не имеет практической ценности.

Уууу, вы какие. (с)Г. Хазанов.

INKEY$ при нажатии не имеющих ASCII кода клавиш возвращает строку не из одного символа, как обычно, а из двух: нулевой символ (CHR$(0) и символ chr$(скан-код клавиши).

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

REM Программа 20.1
CONST a = "*"
DIM drawflag%
DIM up AS STRING
DIM down AS STRING
DIM left AS STRING
DIM right AS STRING
DIM f1 AS STRING
up = CHR$(72)
left = CHR$(75)
right = CHR$(77)
down = CHR$(80)
f1 = CHR$(59)
drawflag% = 0
x = 15
y = 15
CLS
DO
  LOCATE y, x: PRINT a;
  ch$ = INKEY$
  IF ch$ = CHR$(27) THEN END
  IF MID$(ch$, 1, 1) = CHR$(0) THEN ch$ = MID$(ch$, 2, 1)
  SELECT CASE ch$
    CASE up
      IF NOT drawflag% THEN LOCATE y, x: PRINT " ";
      y = y - 1
      IF y < 1 THEN y = 1
      LOCATE y, x: PRINT a;
    CASE left
      IF NOT drawflag% THEN LOCATE y, x: PRINT " ";
      x = x - 1
      IF x < 1 THEN x = 1
      LOCATE y, x: PRINT a;
    CASE right
      IF NOT drawflag% THEN LOCATE y, x: PRINT " ";
      x = x + 1
      IF x > 80 THEN x = 80
      LOCATE y, x: PRINT a;
    CASE down
      IF NOT drawflag% THEN LOCATE y, x: PRINT " ";
      y = y + 1
      IF y > 23 THEN y = 23
      LOCATE y, x: PRINT a;
    CASE f1
      drawflag% = NOT drawflag%
      LOCATE 24, 1
      IF drawflag% THEN PRINT "#";  ELSE PRINT " ";
  END SELECT
LOOP WHILE 1

Эта программа позволяет управлять движением звездочки, а заодно и рисовать при включенном режиме рисования. Для включения/выключения этого режима надо нажать F1.

Программа достаточно проста (если вы так не считаете, то напишите мне письмо с указанием непонятных мест и я вам все объясню), новым для вас является лишь реагирование на курсорные и функциональные клавиши.

Для таких клавиш, как уже было сказано, INKEY$ возвращает строку из двух символов. Для того чтобы работать с одним символом строки служит функция MID$(строка,нач_символ, число).

Эта строка возвращает подстроку, начиная с позиции нач_символ и длиной в число символов. Короче, подробнее читайте об этом ниже.

Так вот, мы должны проверить, что из себя представляет первый символ возвращаемой INKEY$ строки. Если он нулевой (равен CHR$(0)), то нужно проверить второй символ. Это будет CHR$(скан-код). Т.е. для "стрелки вправо" второй символ будет равен CHR$(77), т.к. скан-код "стрелки вправо" - 77. Скан-коды указаны в хелпе к Бейсику.

Еще обратите внимание, для того чтобы заставить объект на экране двигаться, нужно стереть его с экрана, вычислить новые координаты и снова нарисовать.

Товарищ прапорщик, запишите эти простые, но мудрые слова. (с) ДМБ.

Вывод информации

Вывод осуществляется с помощью оператора PRINT.

Что можно к этому добавить?

Первое. Вы можете управлять позицией печати, т.е. указывать ее. PRINT печатает свои аргументы начиная с текущей позиции курсора. Вы можете установить эту позицию с помощью оператора LOCATE row,col.

Здесь row это номер строки экрана от 1 (самая верхняя) до 24 (предпоследняя снизу), а col - номер столбца от 1 (самый левый) до 80 (самый правый). Учтите, что числа приведены для текстового режима 80x25, в других режимах размер экрана в знакоместах (или пикслелах для графических режимов) будет другим.

Напечатав все свои аргументы PRINT выставляет позицию печати в начало следующей строки, т.е. печатает CHR$(13). Чтобы он этого не делал, нужно завершить запись оператора точкой с запятой, которая говорит ему, чтобы он установил курсор в следующую за напечатанным символом позицию.

Сравните:

PRINT "Line 1"
PRINT "Line 2";
PRINT "LINE 2 AGAIN"

Следующий момент это форматированный вывод.

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

Форматированный вывод это процесс вывода информации с предварительным ее форматированием, т.е. приданием ей определенного формата.

Оператор PRINT USING используется для этого дела. В отличие от простого PRINT'а, кроме аргументов нужно еще указать строку формата или шаблон.

Шаблон должен содержать специальные символы (посмотрите их все в хелпе к Бейсику).

Это например "#" для цифры. Если шаблон состоит из 5 таких символов, то выводимые числа будут занимать 5 позиций. Если число меньше (например,123) то спереди будут добавлены пробелы.

Кажется, что это довольно удобное средство для вывода таблиц. Да, но есть один недостаток из-за которого мне все это и не нравится. Если в данном примере число будет состоять из более, чем 5 символов, то оно будет напечатано целиком с предваряющим символом "%", т.е. вся табличка будет испорчена.

Поэтому с этим PRINT USING надо вести себя осторожно и применять его только в "безопасных" ситуациях.

Кроме того вы можете указать не только общее число цифр. А еще и число цифр после десятичной запятой. Можно также автоматически расставить запятые через каждые три цифры, т.е. отделить тысячи, миллионы и т.п. И автоматически приписывать знак бакса. Все это может пригодиться при выводе на экран денежных сумм. Ниже будет пример.

Форматирование строк тоже возможно. Правда, если бы его придумывали мы с вами, то оно имело бы гораздо больше возможностей. Возможно, мы все еще придумаем.

Вы можете распечатать всю строку без изменений ("&"), только первый символ ("!") или N+2 первых символов("\ \"), где N - число пробелов между слешами. Также можно добавить в начало или конец строки произвольные символы.

Давайте попробуем написать программку для генерации именного чека.

REM Программа 20.2

REM Определяем переменные DIM f$, i$, o$, sum$, nal$, sda$, pat$

REM Вводим исходные данные CLS PRINT : PRINT "Введите данные о клиенте." INPUT " Фамилия:", f$ INPUT " Имя:", i$ INPUT "Отчество:", o$ PRINT : PRINT "Введите данные о платеже:" INPUT " Сумма:", sum$ INPUT "Наличными:", nal$ INPUT " Сдача:", sda$

'Обратите внимание, что мы используем 'строковые переменные для ввода 'числовой информации.

REM Рисуем чек CLS PRINT CHR$(201)+STRING$(23,205)+CHR$(187) PRINT CHR$(186); PRINT " OOO " + CHR$(34) + " ProgForBeg" + CHR$(34); PRINT " "+CHR$(186) PRINT CHR$(199)+STRING$(23,196)+CHR$(182) PRINT CHR$(186);" "; DATE$; " "; TIME$;" "; CHR$(186) PRINT CHR$(199)+STRING$(23,196)+CHR$(182) PRINT CHR$(186)+" Покупатель: "+CHR$(186) PRINT CHR$(186)+" "+CHR$(186) PRINT CHR$(199)+STRING$(23,196)+CHR$(182) PRINT CHR$(186)+" Сумма: "+CHR$(186) PRINT CHR$(186)+" Налич: "+CHR$(186) PRINT CHR$(186)+" Сдача: "+CHR$(186) PRINT CHR$(199)+STRING$(23,196)+CHR$(182) PRINT CHR$(186)+" СПАСИБО! "+CHR$(186) PRINT CHR$(200)+STRING$(23,205)+CHR$(188)

'В оригинале программа выглядела по-другому, но из-за 'невозможности передать здесь псевдографику, я заменил 'псевдографические символы функцией CHR$() с их кодами. 'Табличка, где собраны все полезные псевдографические 'символы и их коды есть на сайте (см. ссылку выше в этом 'выпуске). 'Функция STRING$(number, code|symbol) возвращает строку из 'number символов symbol или из number символов 'с ASCII кодом code. В программе эта функция возвращает 'строки состоящие из 23 символов с кодами 196 или 205 (это 'одиночная и двойная горизонтальные линии). 'CHR$(34) это кавычки. 'Функции DATE$ и TIME$ возвращают строки, содержащие 'текущие дату и время соответственно.

REM Заполняем чек LOCATE CSRLIN - 8, 3 PRINT f$; PRINT USING " !."; i$; o$; pat$ = "**##,####.##" LOCATE CSRLIN + 2, 12 PRINT USING pat$; VAL(sum$) LOCATE CSRLIN, 12 PRINT USING pat$; VAL(nal$) LOCATE CSRLIN, 12 PRINT USING pat$; VAL(sda$)

'Заполнение чека мной отделено от его рисования. Это 'необязательно, но по-моему так лучше. 'В операторе LOCATE в качестве первой координаты 'несколько раз использована функция CSRLIN. Она возвращает 'номер текущей строки,т.е. строки, где в данный момент 'стоит курсор. Чтобы получить текущую позицию курсора в 'строке нужно использовать функцию POS(0). Аргумент ей 'нужен, но может быть любым числом. 'Фамилию мы печатаем как есть, а вместо имени и отчества - 'инициалы. Шаблон " !." означает, что сначала делается 'отступ (пробел), потом печатается первый символ строки(!), 'затем точка(.). 'Шаблон для печати денежных сумм задается с помощью переменной 'pat$. Его длина определяет максимальное количество цифр в 'печатаемом числе. Точка это десятичный разделитель, т.е. 'отделяет целую часть от дробной, которая может иметь максимум 'два знака. Две звездочки указывают на то, что число будет 'дополнено слева звездочками до длины шаблона.

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

На запрос программы введите исходные данные, например, такие:

Введите данные о клиенте.
 Фамилия:Министратор
     Имя:Александр
Отчество:Данилович

Введите данные о платеже: Сумма:10209.36 Наличными:11536 Сдача:1326.64

Как только вы введете сдачу, на экране появится готовый чек (вообще-то в программе использована псевдографика, но в Windows, где делается рассылка, использованные символы отсутствуют):

+-----------------------+
¦   OOO " ProgForBeg"   ¦
¦-----------------------¦
¦ 06-11-2001   15:24:00 ¦
¦-----------------------¦
¦ Покупатель:           ¦
¦ Министратор А. Д.     ¦
¦-----------------------¦
¦ Сумма:   ****10209.36 ¦
¦ Налич:   ****11536.00 ¦
¦ Сдача:   *****1326.64 ¦
¦-----------------------¦
¦       СПАСИБО!        ¦
+-----------------------+

Какой недостаток у этой программы?

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

Что бросается в глаза, так это дата в американском формате мм-дд-гггг, а не в нашем чч.мм.гггг. Кстати, древнейший Бейсик нормально себя чувствует в двадцать первом веке, вы не находите?

Время с точностью до секунд нам тоже не нужно.

Кто виноват мы знаем. Но что же делать?

Переходить к следующему пункту повестки дня.

Обработка символьной информации

Как обрабатывать числа мы знаем со школы. Их можно складывать умножать, возводить в степень, находить синус и тому подобное. А вот что мы можем делать со строками и зачем, вообще, с ними что-то нужно делать.

Ну, кое-какую обработку строк демонстрирует программа 20.2, а именно использование только первой буквы вместо всего слова и добавление нужного количества звездочек в начало строки.

Другими словами, когда требуется так или иначе изменить представление символьной информации мы приходим к необходимости ее обработки (само слово "обработка", естественно, имеет более широкий смысл).

Встроенные возможности, которые предоставляет язык программирования различны для разных языков. Например, PERL, заточенный под обработку текстов, имеет гораздо больше таких возможностей, чем Бейсик.

Однако, нам придется довольствоваться последним.

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

Мы можем узнать, есть ли в строке необходимый нам символ или подстрока, и если есть, то где (с какой позиции начинается).

Если строка имеет ведущие или завершающие "незначащие" пробелы, то мы можем их отбросить.

Мы можем складывать строки. Можем создавать строки из нужного нам количества одинаковых символов. И, вообще, любые строки.

Рассмотрим все это на практике. И для начала разберемся с датой и временем.

Функция TIME$ возвращает нам строку вида "чч:мм:сс" (часы:минуты:секунды). Мы не можем влиять на возвращаемый результат, но нам это и не надо.

Допустим нам не нужны секунды, т.е. из возвращаемой TIME$ строки нам нужны только 5 первых символов.

Воспользуемся функцией выделения подстроки. Таких функций три: LEFT$(),MID$() и RIGHT$(). Они возвращают нужное количество символов слева, из произвольного места и справа указанной строки.

Примеры:

a$="Сегодня 11.06.2001. Время 16:56"

LEFT$(a$,4) = "Сего" RIGHT$(a$,5) = "16:56" MID$(a$,9,10) = "11.06.2001" MID$(a$,15,1) = "2"

Первым аргументом во всех этих функциях является строка, которая может быть задана как переменной, так и константой. В примере это переменная a$.

Второй аргумент функций LEFT$() и RIGHT$() это число символов, которые нужно "изъять" из строки. Изъять в кавычках, потому что реально переменная не изменяется.

Второй аргумент функции MID$() это позиция, с которой нужно начать "изъятие" символов, а третий - количество символов.

Есть и оператор MID$, который не "изымает", а вставляет в одну строку другую. Посмотрите хелп, если вам нужны подробности.

Теперь, чтобы привести дату и время к желаемому виду, мы должны сделать следующее изменение в программе 20.2:

 Было:
------
PRINT CHR$(186);" "; DATE$; "   "; TIME$;" "; CHR$(186)
Стало:
------
DIM MYDATE$,MYTIME$
 ...
MYDATE$=MID$(DATE$,4,2)+":"+LEFT$(DATE$,3)+RIGHT$(DATE$,4)
MYTIME$=LEFT$(TIME$,5)
PRINT CHR$(186);" "; MYDATE$; "   "; MYTIME$;" "; CHR$(186)

Стало сложнее. Да, а вы как хотели. Искусство требует жертв.

А зачем нам нужна длина строки? Часто, когда пользователь имеет возможность ввести строку и ее длина не задана жестко, нужно эту длину определять. Или же мы сами хотим ограничить длину, например, пароля снизу пятью символами, а сверху пятнадцатью.

Длину строки нам может сообщить функция LEN().

Примеры:

Задание пароля
--------------

DO CLS PRINT "Задайте пароль (5-15 символов):"; pass$ = "" DO DO ch$ = INKEY$ LOOP WHILE ch$ = "" IF ch$ <> CHR$(13) THEN PRINT "*"; pass$ = pass$ + ch$ END IF LOOP UNTIL ch$ = CHR$(13) LOOP UNTIL LEN(pass$) >= 5 AND LEN(pass$) <= 15 PRINT : PRINT "Ok"

Слово в рамочке ---------------

INPUT "Введите слово:",word$ l=LEN(word$) PRINT "+";STRING$(l+2,"-");"+" PRINT "| ";word$;" |" PRINT "+";STRING$(l+2,"-");"+"

Печать по вертикали -------------------

INPUT "Введите слово:",word$ l=LEN(word$) FOR i=1 TO l PRINT MID$(word$,i,1) NEXT i

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

Действительно, имея в запасе цикл и функцию MID$ можно вытворять со строками самые невообразимые вещи. Можно пройтись в цикле по строке и переставить все буквы, выкинуть лишние, добавить новые и т.п.

Пример:

Перевертыши
-----------

INPUT "Введите слово:",word$ l=LEN(word$) temp$="" FOR i=l TO 1 STEP -1 temp$=temp$+MID$(word$,i,1) NEXT i PRINT word$;"-->";temp$

В примерах запрашивается слово. Но реально нигде не проверяется, сколько слов во введенной строке. Как это сделать?

Я говорил, что можно узнать, есть ли искомый символ в строке и если есть, в в какой позиции он стоит.

Для этого служит функция INSTR().

INSTR([начало,]строк_выражение1$,строк_выражение2$)

Начало устанавливает позицию символа, откуда начинается поиск. Если начало опущено, INSTR начинает поиск с позиции 1.

Строк_выражение1$ - строка, которую ищут, строк_выражение2$ - строка, в которой ищут.

Функция возвращает позицию, в которой начинается искомая подстрока в строке или 0, если подстрока не найдена.

Примеры:

Сколько слов?
-------------

INPUT "Введите несколько слов, разделенных пробелом:", words$ c=0 'инициализируем счетчик слов. i = 1 'начало слова. DO j = INSTR(i, words$, " ") 'находим пробел (конец слова). IF j = 0 THEN j = LEN(words$) + 1 'если пробел не найден (это 'последнее слово), то устанавливаем 'конец вручную. PRINT MID$(words$, i, j - i) 'печатаем слово. i = j + 1 'устанавливаем начало следующего 'слова на символ, идущий за 'пробелом. c=c+1 'увеличиваем значение счетчика 'слов. LOOP UNTIL j = LEN(words$) + 1 'если j имеет такое значение, то 'значит последнее слово уже 'напечатано.

Долой гласные --------------

glasnye$ = "AEIOUYaeiouyАЕЁИОУЭЫЮЯаеёиоуэыюя" 'строка с гласными.

INPUT "Введите слово:"; word$ l = LEN(word$) temp$ = "" FOR i = 1 TO l ch$ = MID$(word$, i, 1) 'выделяем символ. IF INSTR(glasnye$, ch$) = 0 THEN temp$ = temp$ + ch$ 'если он не найден в 'строке гласных, то 'прибавляем его к 'результирующей строке. NEXT i PRINT word$; "-->"; temp$

Обратите внимание на пример "Долой гласные". На таком же принципе основаны и различные перекодировщики (из одной кодировки в другую). Только там не строка с гласными, а несколько строк (по числу кодировок) с русским алфавитом. Алфавит у нас один, но эти строки будут разными, т.к. различны коды русских букв в разных кодировках.

Входные данные посимвольно анализируются. Берется символ, ищется в строке исходной кодировки с помощью INSTR. После этого мы имеем число, т.е. позицию буквы в алфавите, например, 12 для "К".

Далее берется строка кодировки назначения и из нее, с помощью MID$, берется символ, стоящий в определенной ранее позиции. Этот символ выводится (на экран, в файл и т.п.).

Принцип, как видите, прост.

Чтобы перевести число в символьную строку нужно использовать функцию STR$(). Это может понадобиться, например, когда мы хотим узнать, сколько цифр в числе.

О, да, математики вы мои, можно делить это число в цикле, до тех пор пока не получится ноль, а заодно, считать число делений.

Но гораздо проще перевести число в строку и найти ее длину с помощью LEN.

f=10
PRINT LEN(STR$(f))

Эта программа напечатает 3. Не пугайтесь, просто один символ отведен под знак, а плюс, ведь, мы никогда почти не пишем, поэтому вместо него стоит пробел. Единичку отнимаем и получаем число цифр.

Однако если пробел нам мешает, можно от него избавиться, воспользовавшись функцией LTRIM$(), которая "обрезает" у строки все ведущие пробелы. А RTRIM$() делает то же самое с замыкающими пробелами.

Это может потребоваться, когда вы читаете текстовый файл с таблицей вида:

+-------------+--------------------+------------+
!Имя          !Фамилия             !  Телефон   !
+-------------+--------------------+------------+
!Василий      !Пупкин              ! 128-34-843 !
!Герасим      !Дворников           ! 432-43-982 !
!             !                    !            !

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

Примерно так может обрабатываться одна строка:

i = 2
j = INSTR(i, stroka$, "!")
mname$ = RTRIM$(MID$(stroka$, i, j - i))
i = j + 1
j = INSTR(i, stroka$, "!")
mfamily$ = RTRIM$(MID$(stroka$, i, j - i))
i = j + 1
j = INSTR(i, stroka$, "!")
mphone$ = LTRIM$(RTRIM$(MID$(stroka$, i, j - i)))

Я изложил вам основы работы со строками в Бейсике. Более сложные приемы основаны на комбинировании этих основных приемов.

ОКРУЖЕНИЕ .::. Си для начинающих

C и C++ для начинающих, возможно ли это?

Отвечает av, ведущий рассылки "C и C++ для начинающих":

... Я уже начал получать письма. Преимущественно пишут, что С не знают вообще или знают очень слабо и что хотели бы научиться. Значит, правильно я сделал, что начал рассказывать с нуля. Что ж, дерзайте! Берите все выпуски, начиная с первого, читайте, вникайте и (еще раз повторюсь) выполняйте домашние задания! И все у вас получится.

От себя добавлю, что неплохо бы еще и на рассылку-то подписаться. Изучение Си у вас пойдет как по маслу, особенно, если эту рассылку вы читали внимательно.

Кстати, где у нас господин mssss? Эй, если Вы еще не изучили Си++, то у Вас появился еще один шанс сделать это. Желаю удачи!

Рассылки Subscribe.Ru
C и C++ для начинающих

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

С уважением,
Вячеслав Stac Мацнев mailto:stac@stacmv.net
11.06.01.



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться Рейтингуется SpyLog

В избранное