|
Полезные функции Выкладываем полезные функции, чтоб не изобретать велосипед заново... |
10.08.2012, 14:36
|
#1
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Возвращение нескольких результатов из функции + Разбиение строки по символу
Метод №1: использование глобальных массивов.
У этого метода есть ограничение, о котором ниже, но для простых каких-то задач сгодится.
Как альтернатива - свои списки (упрощённые) использовать ( может допишу с ними пример сделал, ниже по теме "метод №2").
Была задачка разбить строку на подстроки по знаку-разделителю. Я захотел вернуть массив строк.
Просто через "Return mas" блитц не умеет. Поэтому я сделал глобальный массив для хранения результатов работы функции.
;инфа для возврата значений из функций
Dim RETVAL_STR$(0)
Global RETVAL_COUNT%
;smb - 1 символ типа запятой
Function fnSplitString(s$,smb$=",")
Local size% = Len(s)
Local cnt% = 0, k%
;сначала находим количество символов-разделителей
For k% = 1 To size
If(Mid(s,k,1) = smb) Then cnt = cnt + 1
Next
RETVAL_COUNT = cnt+1 ;запоминаем размер
Dim RETVAL_STR(cnt) ;расширяем до нужного размера
If(cnt = 0)
RETVAL_STR(0) = s
Return
EndIf
;теперь снова проходим, заполняя глобальный массив
Local val$ = "", char$, ind% = 0
For k% = 1 To size
char = Mid(s,k,1)
If(char = smb)
RETVAL_STR(ind) = val
val = ""
ind = ind+1
Else
val = val + char
If(k = size) Then RETVAL_STR(ind) = val ;последнюю подстроку тоже
EndIf
Next
End Function
На оптимальность работы функции я не претендую, мне нужно от неё парсить параметры в строчках типа
в момент загрузки уровня.
Пример использования:
fnSplitString("100,exit,-7")
For k% = 0 To RETVAL_COUNT-1
DebugLog("RETVAL_STR("+k+") = "+RETVAL_STR(k))
Next
Теперь о грустном. Вот это работать будет криво или загнётся:
Local s1$ = "0,0;1,0;1,1;0,1", s2$
fnSplitString(s1, ";") ;сначала разбиваем по точке-с-запятой
For k% = 0 To RETVAL_COUNT-1
DebugLog("RETVAL_STR("+k+") = "+RETVAL_STR(k))
fnSplitString(RETVAL_STR(k),",") ;теперь по запятой
For i% = 0 To RETVAL_COUNT-1
DebugLog("RETVAL_STR_2("+i+") = "+RETVAL_STR(i))
Next
Next
Очередной вызов функции затрёт массив, который используется в другом месте.
Последний раз редактировалось Жека, 13.08.2012 в 08:23.
Причина: Поправил мелочи, назвал это метод №1
|
(Offline)
|
|
10.08.2012, 15:09
|
#2
|
AnyKey`щик
Регистрация: 24.06.2012
Сообщений: 16
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Жека
Dim RETVAL_STR(cnt) ;расширяем до нужного размера
If(cnt = 0)
Dim RETVAL_STR(0)
RETVAL_STR(0) = s
Return
EndIf
|
Зачем еще раз "Dim RETVAL_STR(0)" делаешь, если cnt и так будет 0? И Dim с нулем удаляет массив, нужно Dim 1 делать.
Сообщение от Жека
If(k = size) Then RETVAL_STR(ind) = val ;последнюю подстроку тоже
|
Это вообще вынести из цикла, причем без условия "If(k = size)"
Переменная k не определена как Local.
Как вариант можно передавать через параметры функции статические массивы, просто заранее определить максимальный размер, некрасиво конечно, но как вариант.
Ну а насчет затирания предыдущих результатов, если не лень, можно написать для каждого типа парсинга свой вариант
ЗЫ
По коду еще, мне кажется для длинных строк будет эффективнее сделать авторазмер массива ( как например в С++ std::vector, каждый раз в два раза ), нежели сначала делать предрасчет.
Правка: забыл что в блице нет ReDim и новый Dim удаляет старые данные.
Ну и в крайнем случае можно банки использовать, неудобно конечно что встроеного PokeString нету.
|
(Offline)
|
|
10.08.2012, 18:26
|
#3
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Hartmann1
Зачем еще раз "Dim RETVAL_STR(0)" делаешь, если cnt и так будет 0? И Dim с нулем удаляет массив, нужно Dim 1 делать.
|
Нифига не удаляет, я проверял. Лишний дим забыл убрать, спасибо, сначала хотел ветку елсе делать.
Это вообще вынести из цикла, причем без условия "If(k = size)"
|
Можно.
Переменная k не определена как Local.
|
Некритично.
Как вариант можно передавать через параметры функции статические массивы, просто заранее определить максимальный размер, некрасиво конечно, но как вариант.
|
Вот про это подробнее, пожалуйста, если это не из серии забыл что речь о блитце.
Спасибо за комменты
|
(Offline)
|
|
10.08.2012, 19:30
|
#4
|
AnyKey`щик
Регистрация: 24.06.2012
Сообщений: 16
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Жека
Нифига не удаляет, я проверял.
|
Как ты проверял?
Сообщение от Жека
Некритично.
|
Тем не менее твой код может заюзать какой-нить невнимательный нуб, у которого окажется глобальная k (и не такие бывают же
Сообщение от Жека
Вот про это подробнее, пожалуйста, если это не из серии забыл что речь о блитце.
|
А чего подробнее, через параметры можно передавать массивы с квадратными скобками, статические которые. В твоем случае будет
fnSplitString(s$,smb$=",",strings$[константный размер])
Только вот я не подумал что передавать-то туда нужно такого же размера массив Короче лучше банки юзать.
А еще лучше хранить данные в бинарном виде
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
11.08.2012, 07:48
|
#5
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Hartmann1
Как ты проверял?
|
Dim a$(0)
a(0) = "hi world!"
DebugLog(a(0))
пашет отличненько-с (я сам удивился, но раз оно так, то что поделать?)
Глобальная К - опасно, сам такое не сделаю, но всё же полезно при написании кода на экспорт людям.
"Массивы с квадратными скобками" - для данного примера не сгодятся, но на будущее припомню.
|
(Offline)
|
|
11.08.2012, 13:04
|
#6
|
AnyKey`щик
Регистрация: 24.06.2012
Сообщений: 16
Написано 5 полезных сообщений (для 6 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Жека
Dim a$(0)
a(0) = "hi world!"
DebugLog(a(0))
пашет отличненько-с (я сам удивился, но раз оно так, то что поделать?)
|
Глянул справку и точно ведь, я забыл что в блице выделяется на 1 элемент больше чем указано
Кстати -1 тоже корректный размер, и судя по тому что доступ к нулевому элементу вызывает "index out of bounds", память освобождается.
|
(Offline)
|
|
13.08.2012, 08:47
|
#7
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Метод №2: использование связных списков
Здесь пример использования подобия связного списка для возвращения неограниченного числа параметров из функции.
;создание списка с параметрами - головной узел
Function fnRetValCreate.TRetVal(s$="", i%=0, f#=0)
Local rv.TRetVal = New TRetVal
rv\root = rv
rv\sVal = s
rv\iVal = i
rv\fVal = f
Return rv
End Function
;добавление нового результата
Function fnRetValAdd.TRetVal(retval.TRetVal, s$="", i%=0, f#=0)
;если ещё не создан, то создаём новый
If(retval = Null) Then Return fnRetValCreate(s, i, f)
retval\nxt = New TRetVal
retval\nxt\root = retval\root
retval\nxt\sVal = s
retval\nxt\iVal = i
retval\nxt\fVal = f
Return retval\nxt
End Function
;удаление всех результатов
Function fnRetValDelete(retval.TRetVal)
Local node.TRetVal = retval\root
While(node <> Null)
retval = node
node = node\nxt
Delete(retval)
Wend
End Function
;тип для хранения результатов (строки, целые и дробные)
Type TRetVal
Field sVal$, iVal%, fVal# ;сами данные
Field nxt.TRetVal ;указатель на следующего
Field root.TRetVal ;указатель на головной узел
End Type
Для примера использования этого метода ниже представлена функция выценления параметров командной строки - с учётом того, что часть параметров может быть заключена в кавычки, а часть просто через пробел.
Local cl$ = CommandLine()
If(cl = "") Then End
DebugLog(cl)
Local rv.TRetVal = fnParseCommandLine(cl)
Local node.TRetVal = rv
Local file% = WriteFile("files.txt")
;пробегаем по всем результатам
While(node <> Null)
WriteLine(file, node\sVal)
node = node\nxt
Wend
CloseFile(file)
;удаляем список с результатами
fnRetValDelete(rv)
End
;в командной строке параметры, содержащие пробелы, обрамляются кавычками
;остальные - нет
Function fnParseCommandLine.TRetVal(cl$)
Local size% = Len(cl)
Local k%, cnt%, s$="", char$, q$ = Chr(34) ;кавычка
Local retval.TRetVal
For k% = 1 To size ;проходим по всем буквам
char = Mid(cl, k, 1)
If(char = q) ;встретилась кавычка
cnt = cnt+1
DebugLog("1")
If(cnt = 2) ;закрылась кавычка
retval = fnRetValAdd(retval, s)
s = ""
k = k+1 ;пропускаем пробел
cnt = 0
EndIf
Else If(char = " " And cnt = 0) ;если пробел не внутри кавычек, то он отделяет параметры
retval = fnRetValAdd(retval, s)
s = ""
DebugLog("2")
Else
s = s + char
If(k = size) ;если достигли конца строки, то последний параметр забираем тоже
DebugLog("3")
retval = fnRetValAdd(retval, s)
EndIf
EndIf
Next
Return retval\root ;возвращаем указатель на корень списка
End Function
ПС. Если кто-то знает как в блитц максе выцепить из командной строки русские символы, то подскажите - нужно такое: кидаем файл, содержащий в пути или названии кириллицу, на ехе-шник, и нужно достать/преобразовать путь так, чтоб можно было сделать с ним LoadImage() и прочее.
|
(Offline)
|
|
10.11.2012, 05:36
|
#8
|
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Эээээ так это ты так с БМаксом изголяешься??? 0_о
На БМаксе так делать это всеравно что с куклой на свидание сходить =)
В БМаксе функции могут возвращать что угодно, хоть массивы, хоть контейнеры.
Ну а если надо указать прямо, то для таких целей там есть специальный оператор - "Var", который передает прямой адрес переменной.
|
|
|
10.11.2012, 12:11
|
#9
|
Дэвелопер
Регистрация: 17.01.2007
Сообщений: 1,552
Написано 351 полезных сообщений (для 774 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
написано же, раздел для Blitz3D...
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
30.11.2012, 11:47
|
#10
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Diablo1909, мои примеры выше для Blitz3D.
Научи меня вот этому:
Если кто-то знает как в блитц максе выцепить из командной строки русские символы, то подскажите - нужно такое: кидаем файл, содержащий в пути или названии кириллицу, на ехе-шник, и нужно достать/преобразовать путь так, чтоб можно было сделать с ним LoadImage() и прочее.
|
|
(Offline)
|
|
30.11.2012, 17:13
|
#11
|
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Кирилицу в названиях файла всегда надо убирать. Ибо не везде работает.
|
|
|
Сообщение было полезно следующим пользователям:
|
|
03.12.2012, 06:50
|
#12
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Приходится убирать Я для себя утилитки пишу, поэтому универсальность не нужна.
|
(Offline)
|
|
28.12.2012, 16:29
|
#13
|
AnyKey`щик
Регистрация: 27.08.2007
Сообщений: 17
Написано одно полезное сообщение
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Жека
Метод №1: использование глобальных массивов.
На оптимальность работы функции я не претендую, мне нужно от неё парсить параметры в строчках типа
|
Я конечно в этом мало понимаю, но что если юзать либо списки (type), либо банки?
|
(Offline)
|
|
28.12.2012, 16:33
|
#14
|
AnyKey`щик
Регистрация: 27.08.2007
Сообщений: 17
Написано одно полезное сообщение
|
Ответ: Возвращение нескольких результатов из функции + Разбиение строки по символу
Сообщение от Hartmann1
Ну и в крайнем случае можно банки использовать, неудобно конечно что встроеного PokeString нету.
|
Так его написать, две минуты времени нужно
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:09.
|