Воскресенье, 19.05.2024, 04:19
Personal dimanche13 site
Главная | Регистрация | Вход Приветствую Вас Гость | RSS
Категории каталога
Мои статьи [22]
BlitzMax [17]
раздел содержит статьи относящиеся к языку программирования BlitzMax
SDL [9]
раздел содержит статьи на тему SDL
Code::Blocks [3]
в этом разделе рассказывается как прикрутить движок к интегрированной среде разработки(IDE) Code::Blocks
Форма входа
Поиск
Друзья сайта
Главная » Статьи » BlitzMax

Всплывающая подсказка или трактат о строках

Всплывающая подсказка или трактат о строках


Миллиарды спелых строк
И не пойманных дорог,
К тебе,
Под ноги,
Чтоб ты сумел их приручить
Навеки.
Е.Летов

Содержание:

  1. Введение
  2. Про строки и символы
  3. Slices
  4. Методы
  5. Перенос по словам
  6. Перенос по буквам
  7. Выведение

Введение

Привет! Этот тутор возник совсем спонтанно. Один мой товарищ никак не мог разобраться со всплывающей подсказкой для своей игры. Эта вещь есть почти в каждой игре. Когда в инвентаре или магазине или еще где-то, наводишь мышью на объект, должен высветиться хелп по этому предмету/ заклинанию/ оружию/ юниту. Но не просто одной строкой, а желательно в красивой рамочке, и что бы текст, переносился по буквам или по словам на новую строку, по достижению края рамки. И тут на форуме открылся опрос «Как вы храните диалоги в игре» или еще какое-то подобное название. Я высказал свою точку зрения, о том что лучше хранить все в тексте, а не в картинках. Текст надо подчинять себе и правилам игры, для которой он написан — сказал я. И дабы не быть голословным, я как раз начал заниматься системой диалогов, в которой нужны были выполняться те же условия, что и во всплывающей подсказке, то есть перенос по словам. Первые результаты, я отправил своему товарищу по почте, на примере с подсказкой. И он предложил мне написать об этом статью. Чтож, вот и она. К вашим услугам.

Про строки и символы

Начну я как всегда из далека, давно уж сложилась такая традиция. Для начала давайте поймем, что же такое строка. Строка — это набор букв, знаков препинания и других печатных символов, скажете вы. Да, пожалуй, я с этим соглашусь. Но с точки зрения программиста, строка — это одномерный массив, содержащий символы. Сейчас, я покажу вам одну такую строку. Вот она: классика программирования «Hello World!». Посмотрите на рисунок: 


H

e

l

l

o


W

o

r

l

d

!

0

1

2

3

4

5

6

7

8

9

10

11

Я изобразил нашу строку в виде массива: здесь каждая буква имеет свою позицию, буква «Н» к примеру, стоит в ячейке с номером 0, «е» — в ячейке с номером 1 и так далее. Всего 12 ячеек от 0 до 11. А что, если мы захотим узнать какая 6 (шестая) буква в нашем предложении? Ну а так как строка, это массив символов, почему бы не обратиться к нашей строке как к массиву? Да! И в Бмаксе такая возможность существует. Ок, попробуем.

print mystring[6]

Блин, какая-то цифра выскочила вместо буквы. Да, я слукавил, не все так просто. Строка - это массив символов, но в этом массиве хранятся не сами символы, а их номера из таблицы кодировки символов. В такой таблице, за каждой буквой закреплен ее номер. Существует множество кодировок. Но в осном сейчас используют Unicode. Ага, теперь мы знаем, что в массиве строки хранятся не сами буквы, а числа, которые обозначают позицию буквы в таблице кодировки.
 
 

72

101

108

108

111

32

87

111

114

108

100

33

0

1

2

3

4

5

6

7

8

9

10

11



Чтоже дальше? Как нам напечатать букву по ее индивидуальному номеру? Такая функция называется Chr(code:int) она принимает в себя код буквы в таблице кодировки, а возвращает саму букву. Так, что шестую букву нашей строки, мы можем напечатать так:
 
print chr(mystring[6])

Надо заметить, что обратная Chr() функция называется Asc(), в качестве аргумента, она принимает символ, а возвращает его код из таблицы кодировки. Например: Print Asc(«H») выведет цифру 72. Давайте теперь узнаем сколько места в памяти занимает наша строка. Это очень просто сделать. Для этого есть специальная функция sizeof() она показывает сколько байт памяти занимает переменная, строка, массив или объект. Исследуемая переменная передается в параметр.
 
Print SizeOf(mystring)

Мы видим, что наша строка занимает 24 байта, а символов в строке 12, то есть в 2 раза меньше. Значит один символ кодируется 2 байтами или 16-битами. Как раз так, как UniCode в Windows.

Slices

Итак из предыдущей части вы поняли, что строка это тот же одномерный массив. А значит, мы можем работать со строкой так же как и с массивом. Это было бы не так весело, если бы Бмакс не предоставлял нам удобные инструменты для работы с массивом. На наше счастье они (эти инструменты) есть! Давайте поплотнее перейдем к слайсам. Английское слово slice означает “кусок”. С помощью слайсов мы можем выделить из массива один или несколько его кусочков. Давайте посмотрим на примере. Вот наша с вами строка: Hello World! С помощью слайсов мы можем разделить ее на две строки, в одной будет слово Hello, а в другой World!

mystring:String = "Hello World!"
firstword:String = mystring[0..5]
secondword:String = mystring[6..12]
Print firstword
Print secondword
 
Действительно, эта программа делает все так как мы и задумали. Но как она это делает? Давайте внимательнее посмотрим на код. Вот так мы выделяем первое слово в переменную строку с подходящим названием firstword:String = mystring[0..5] . Что же означает [0..5] в квадратных скобках? Таким образом мы показываем, что из массива mystring нас интересует фрагмент(кусок) с данными от 0 индекса до 5.
 
 
H
e
l
l
o

 
W
o
r
l
d
!
0
1
2
3
4
5
6
7
8
9
10
11
 
Кстати, две точки между 0 и 5 и есть slice- в терминологии Бмакс. Мы просто выделили начиная с какого и до какого индекса нам нужен кусочек нашей строки/массива и вернули его в переменную firstword. Сама строка mystring осталась такой же, мы не вырезали это слово, а всего лишь скопировали в память и (за)вернули в другую переменную. Заметьте, что здесь написанно до 5, но реально берется кусок с 0 до 4 включительно (5-1). Это надо запомнить. Итак вот вам строка прямо из хелпа, поясняющая принцип использования слайсов:
StringOrArray [ StartIndex .. EndIndex ]
 
 

H

e

l

l

o


W

o

r

l

d

!

0

1

2

3

4

5

6

7

8

9

10

11


secondword:String = mystring[6..12]
 
Глядя на эту строку и пошевелив мозгами, вы без труда разберетесь, как второе слово оказалось в переменной secondword. ;) Ок. Кстати, если мы захотим взять несколько символов с самого начала строки, то 0 индекс можно не писать. И при этом, получим тот же результат. Вот так:
 
firstword:String = mystring[..5]
 
Если же хотим взять кусок от какого-то индекса до конца строки/массива, то можем поступить так:

secondword:String = mystring[6..]
 
Таким образом, зная все это, программу можно упростить:

mystring:String = "Hello World!"
firstword:String = mystring[..5]
secondword:String = mystring[6..]
Print firstword
Print secondword
 
Стоит заметить, что возвращая строку саму в себя после обработки слайсами, все изменения применятся к ней самой. И можно ее изменять и манипулировать ей так, как вам удобно. Это может пригодиться, например, при парсинге строк из какого-нибудь конфигурационного файла. К примеру давайте, уберем из строки символы до 3 и после 9:

mystring:String = "Hello World!"
mystring = mystring[3..10]
Print mystring
 
Вы конечно можете возразить, что для этого есть функции Left, Right, Mid, но посмотрев их код вы увидите, что они сами пользуются слайсами. А если так, то зачем нам лишние функции в программе, если мы знаем как сделать намного проще и понятнее. Ну как, вам нравятся slice-ы?


Методы

Еще одним мощнейшим инструментом для работы со строками, являются методы типа string. То есть каждая переменная, объявленная как :string, является ничем иным, как объектом типа String и имеет набор методов для упрощения работы с данным объектом. Существует большое количество полезных методов, я вам расскажу о самых употребляемых из них. Напомню, название метода пишется через точку после объекта. Метод tolower() переводит строку в нижний регистр, то есть все заглавные буквы станут прописными. Метод toupper() наоборот переводит все символы строки в верхний регистр. Вот парочка наглядных примеров:

littlestring:String = "it`s a little sequence"
bigstring:String ="IT`S A BIG SEQUENCE"
Print littlestring.toupper()
Print bigString.tolower()
 
Еще один метод replace(). Из его названия не трудно догадаться что он делает. Пример:

mystring:String = "Hello World!"
mystring = mystring.Replace("l",".")
Print mystring
 
В этом примере в строке mystring буква “l”, везде где встречается, заменяется на символ ”.” (точка). Можно менять последовательность символов(слова) целиком – mystring.Replace("Hello","GoodBay")
метод find() ищет в строке указанный символ и возвращает его порядковый номер(индекс)

mystring:String = "Hello World!"
Print mystring.find("W")
 
метод contains() сканирует строку, на предмет наличия в ней последовательности символов, которая задается ему в параметр. Так, например, можно узнать содержит ли строка какое-то определенное слово. Возвращает 1 если содержит и 0 если нет.

mystring:String = "Hello World!"
Print mystring.contains("World")
 
Последние 2 метода find() и contains() удобно применять при парсинге файлов, например если у вас есть файл, в котором содержится имя игрока:
 
name=Teodor
 
тогда,примерно так, будет выглядеть проверка на наличие имени

if (not mystring.contains("name")) then error() ' эта строка не содержит name
 
а так, можно прочитать имя:

name:string  = mystring[ mystring.find(“=”)+1 .. ]
 
Как и в любом типе, у типа string есть поля по мимо методов. Поле length возвращает длину строки, подобно функции Len().

mystring:String = "Hello World!"
print mystring.length


Перенос по словам

Итак после маленького вступления перейдем непосредственно к нашей основной задаче: Сделать так, что бы слова нашего текста переносились на другую строку, по достижении какой-то границы. Как уже давно известно, грамотно поставленная задача, содержит половину ответа. Так же известно, что задача любой сложности может быть разбита на ряд более легких задач. Давайте разобьем наше задание на 2 кусочка:
  1. Необходимо, разбить наш текст(строку) на слова
  2. Вывести их согласно заданию, перенося слова на новую строку при достижении края(границы)
Ок. Можно уже создать 2 функции с «говорящими» названиями. Я не большой поклонник Гоголя, но его идея с «говорящими» фамилиями очень подходит для названия функций в программировании. Функцию, что разбивает строку на слова, назовем ParseWords, а вот, собственно, и она:
 
Function ParseWords:TList(_string:String)
        Local List:TList = New Tlist            ' это лист для слов
        Local Word:String                               ' это текущее слово
        For Local i:Int = 0 Until _string.length        ' от 0 и до конца строки
                        If(_string[ i ] = Asc(" "))             'если символ по индексу i пробел, то
                                List.addLast(Word)              'добавляем слово в список
                                Word = Word[..0]                'обнуляем текущее слово
                        Else                                            'а если это не пробел,
                                Word :+ Chr( _string[ i ] )     'то добавляем этот символ к текущему слову
                        End If
        Next
        List.addLast(Word)
        Return List
End Function
 
Как видите функция принимает строку(string), а возвращает список(TList). Я все подробно прокомментировал, так что думаю здесь все понятно. В цикле for-next, я использовал поле length, что равнозначно len(_string), как вы уже знаете. Первая задача решена, переходим ко второй. Функцию мы назовем DrawStrings(WordList:TList, pixelwidth:Int) и она будет принимать 2 параметра - список слов(WordList:TList) и ширину отображаемого участка(pixelwidth:Int), иными словами, координату границы для текста.

Function DrawWords(WordList:TList, pixelwidth:Int)

        Local Result:String
        Local textX:Int = 0
        Local textY:Int = 0
        Local HeightOfText:Int = TextHeight("W")
        For Local ThisWord:String = EachIn WordList             'проходим по всем словам в списке
                If( TextWidth(Result + ThisWord) > pixelwidth ) 'если больше необходимой ширины
                        Result = Result[..0]    'то перенесем это слово на новую строку.
                        TextX = 0                       'х - в ноль
                        TextY :+ HeightOfText   'у - вниз
                EndIf
                Result :+ ThisWord + " "                'добавляем текущее слово к нашей строке
                DrawText(Result, TextX, TextY)   'отображаем нашу строку на экране
        Next
End Function
 
Функция TextWidth() возвращает ширину строки в пикселях, текущего шрифта. Функция TextHeight() возвращает высоту символов в текущем шрифте. Как видите ничего сложного нет. Можно модифицировать функцию, так как вам угодно и удобно. Ввести в параметры начальные координаты текста, шрифт, размер шрифта или что-то другое — все в ваших руках. Весь текст программы смотрите в аттаче.



Перенос по буквам

Перенос по буквам не многим сложнее, переноса по словам. Я написал небольшую программку для демонстрации этого метода. Здесь уже используется ООП подход. За медию большое спасибо Dtamaturg-у. Привожу код, с достаточным количеством комментариев, чтобы понять, что в нем происходит.


Выведение

Эта статья, есть не что иное как простое введение в основы языка Бмакс, включая его специфическую, но от этого не менее простую, работу со строками. Несмотря на кажущуюся простоту, на этом языке можно писать вполне приличные приложения, не только консольные, но и графические. А благодоря своей кросплатформенности (Mac,Linux,Win) и расширяемости возможностей, дополнительными модулями, можно сказать, что этот язык подходит и для более широкого круга задач. К тому же за основу взятый язык Basic получил здесь новый допинг в виде ООП. Чем может понравиться как опытным программистам, так и только начинающим постигать объектно-ориентированный код.
Спасибо за внимание.
 


Источник: http://blitzetc.blitzmax.ru/index.php/Всплывающая_подсказка_или_трактат_о_строках
Категория: BlitzMax | Добавил: dimanche (24.05.2008) | Автор: Dmitriy
Просмотров: 2087 | Комментарии: 1 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Имя *:
Email *:
Код *:
Copyright MyCorp © 2024