PDA

Просмотр полной версии : [Вопрос] Парсинг строк pawn



Sersoftin
28.10.2014, 18:27
Есть строка:
new test[20] = "2014-10-28 00:40:00"; (например)
Есть переменные:
new year, month, day, hour, minut, second; (например)

Необходимо распарсить строку и забить в эти переменные нужные данные.
year = 2014;
month = 10;
day = 28;
hour = 0;
minut = 40;
second = 0;

sscanf отпадает, насколько я понял. Какие есть ещё не геморные способы, дабы не писать это все дело вручную? Может есть что-то.

L0ndl3m
28.10.2014, 21:13
Примерно так:

Функция:


stock ParseString(const str[], dest[][], const maxlength = sizeof(dest[]))
{
new
pos,
count,
offset;

do
{
switch(str[pos])
{
case '-', ' ', ':':
{
strmid(dest[count++], str, offset, pos, maxlength);
offset = pos + 1;
}
}
}
while(str[++pos] != EOS);

if(str[pos] == 0)
strmid(dest[count], str, offset, pos, maxlength);
}


Использование:


main()
{
new
test_string[20] = "2014-10-28 00:40:00";

new
parse_str[6][5],
year,
month,
day,
hour,
minute
second;

ParseString(test_string, parse_str);

year = strval(parse_str[0]);
month = strval(parse_str[1]);
day = strval(parse_str[2]);
hour = strval(parse_str[3]);
minute = strval(parse_str[4]);
second = strval(parse_str[5]);
}


Хотя вряд ли проще чем sscanf.

Sersoftin
28.10.2014, 23:05
Примерно так:

Функция:


stock ParseString(const str[], dest[][], const maxlength = sizeof(dest[]))
{
new
pos,
count,
offset;

do
{
switch(str[pos])
{
case '-', ' ', ':':
{
strmid(dest[count++], str, offset, pos, maxlength);
offset = pos + 1;
}
}
}
while(str[++pos] != EOS);

if(str[pos] == 0)
strmid(dest[count], str, offset, pos, maxlength);
}


Использование:


main()
{
new
test_string[20] = "2014-10-28 00:40:00";

new
parse_str[6][5],
year,
month,
day,
hour,
minute
second;

ParseString(test_string, parse_str);

year = strval(parse_str[0]);
month = strval(parse_str[1]);
day = strval(parse_str[2]);
hour = strval(parse_str[3]);
minute = strval(parse_str[4]);
second = strval(parse_str[5]);
}


Хотя вряд ли проще чем sscanf.

sscanf отрабатывает на строках, где данные разделяются пробелами. Загуглить, как распарсить подобное им я так и не смог. Не нашел инфы.

- - - Добавлено - - -

Думал насчет регулярок, плагин есть по ним. Но там все функции аля составить предкомпилированое регулярное выражение и по нему просто проверить строку, соответствует ли она ему (IsEmailValid, IsPasswordValid). А вытянуть данные по группам или ещё как-то нельзя (вроде :D). В том же C# или java это возможно.

DeimoS
28.10.2014, 23:22
sscanf отрабатывает на строках, где данные разделяются пробелами. Загуглить, как распарсить подобное им я так и не смог. Не нашел инфы.

В sscanf можно установить любой разделитель. Например:

sscanf("6+6+11", "p<+>iii", int1, int2, int3);
Разделителем станет знак сложения. В третьей версии sscanf Y-Less обещал поддержку нескольких разделителей сразу, но пока так и не сделал эту самую версию.
Но ты можешь просто записывать в БД/файл данные в виде, который будет удобночитаем машине. Например, в аккаунте игрока дата будет хранится так:

"2014-10-28 00:40:00"
А уже при записи форматируй её в

2014|10|28|00|40|00
и тогда проблем никаких с конвертированием не будет (а со временем и сам привыкнешь читать данные в таком формате).

Если же речь не о БД идёт, то делай всё наоборот: храни все данные изначально в виде отдельных переменных и уже при надобности их конвертируй в строку.

А вообще тебе изначально стоило озвучить конечную цель (в какой системе это использоваться будет). Может всё гораздо проще

DeimoS
28.10.2014, 23:53
Например, вот способ с использованием sscanf

new test_string[20] = "2014-10-28 00:40:00";
new pos = strfind(test_string, " ", false);
new result[2][11];
strmid(result[0], test_string, 0, pos);
strmid(result[1], test_string, pos+1, strlen(test_string));
new year, month, day, hour, minut, second;
sscanf(result[0], "p<->iii", year, month, day);
sscanf(result[1], "p<:>iii", hour, minut, second);

В виде функции подобное реализовать можно, но не думаю, что оно будет удачнее варианта Londlem

Sersoftin
29.10.2014, 02:12
Система бананов. Если дата разбана больше текущей - юзер в бане. Т.е. все сводится к сравнению даты и времени.

- - - Добавлено - - -

Я вообще изначально спросил: есть ли какие стандартные средства или что-нибудь такое, что не потребует от меня лишних телодвижений и мозговой активности, а вы мне уже готовые функции :) Так не интересно... :) Ну, спасибо, сейчас посмотрим :)

- - - Добавлено - - -

Наверное это будет лучшим выходом. Хранить в типе VARCHAR "2014|10|28|00|40|00" вот такое вот. Разницы не будет, я думаю. И на php взаимодействовать, если что тоже будет нормально. Спасибо всем :)

#ball
29.10.2014, 02:36
Попробуй для бана использовать UnixTime

Sersoftin
29.10.2014, 03:05
Попробуй для бана использовать UnixTime

Да время я по-другому получаю текущее + дату.

DeimoS
29.10.2014, 10:25
Система бананов. Если дата разбана больше текущей - юзер в бане. Т.е. все сводится к сравнению даты и времени.

Как уже и сказали выше, используй UnixTime. Его в любой момент с лёгкостью можно будет перевести в любой формат. И при сравнении проблем не будет

Sersoftin
29.10.2014, 13:40
Как уже и сказали выше, используй UnixTime. Его в любой момент с лёгкостью можно будет перевести в любой формат. И при сравнении проблем не будет

Не кайф к большим числам приближаться... При сравнении и так вроде проблем нет. Хотя памяти он займет поменьше наверное...

DeimoS
29.10.2014, 13:46
не кайф к большим числам приближаться...

Для паролей больше ячеек используется, нежели для будет использовано для хранения времени в формате секунд (сейчас всего 10 ячеек нужно). Да даже для текущей даты, что вы показали в примере, используется гораздо больше ячеек.
Да и в MySQL есть достаточно возможностей для работы с Unix Time (конвертация unixtime в дату/дату в unixtime т.п. Только разобраться нужно).
Это будет всяко лучше, чем конвертировать каждый раз дату и для хранения по 10 переменных создавать.

Nazarik
29.10.2014, 13:50
new date[20] = "2014-10-28 00:40:00";
new year, month, day, hour, minute, second;
sscanf(date, "P<-:>iiiiii", year, month, day, hour, minute,second);