Используем функцию sscanf

Уроки по созданию сервера и готовые решения
Ответить
Grewi
Сообщения: 37
Зарегистрирован: 17 июл 2018, 20:30

Используем функцию sscanf

Сообщение Grewi » 24 июл 2018, 11:06

Введение. Основная информация.
Доброе время суток, участники форума. Достаточно часто пользуюсь функцией sscanf. Почему? Она удобна и практична. Причем использовать ее можно не только в командах, но и, например, при загрузке чего-либо из базы данных, как это делаю я. Допустим, есть система автомобилей. Дабы не создавать два столбца для каждого из двух возможных цветов транспортного средства, можно создать один, в который записывать значение вида "цвет_1, цвет_2". Записать-то запишем, через format:

Код: Выделить всё

format(строка, размер строки, "%d,%d", цвет_1, цвет_2);
Но вот получить из этой строки два значения уже будет проблематично. Приходит нам на помощь sscanf2. Данный плагин уже опубликован на нашем Форуме.
Итак, функция имеет следующие аргументы:

Код: Выделить всё

sscanf(откуда, "<разделитель>типы извлекаемых данных", куда_1, куда_2, ...);
По поводу разделителей. Собственно, это тот символ, которым Вы разделяете введенные данные. Например, если аргументы записаны через запятую, тогда разделитель будет таким: <,>, если вертикальная палочка, <|>, если тире, <->, если пробел, < >. Если у Вас разделителем выступает пробел, тогда < > можно и вовсе не писать.
Что касается типов извлекаемых данных... Есть всего 4 типа:
  • i, d - целые числа (например, "1", "-10", "120");
  • s[размер] - строка (например, "Форум", "Да", "PW");
  • f - дробные числа (например, "17.575", "-47.8", "100.99");
  • u - ID игрока или часть имени (например, "0", "1", "Vasya_Pet", "Vasya_Petrov");
Пример 1.
Вернемся к начальному примеру использования sscanf. В переменную string записаны два цвета: color1 и color2 через запятую. Нам нужно каждый из них увеличить на единицу (инкрементировать). Для этого сначала нужно получить каждый цвет из строки, а затем увеличивать их на единицу. Поскольку цвета имеют целочисленный тип данных, создаем две переменные типа integer:
new color1, color2;
Извлекаем оба цвета, записанных через запятую, из переменной string:

Код: Выделить всё

sscanf(string, "p<,>dd", color1, color2);
Но лучше сделать так, если хотите создать меньшую нагрузку на систему:

Код: Выделить всё

format(string, sizeof(string), "%d, %d", color1++, color2++);
Пример 2.
Извлечем из переменной string три аргумента: UNIX время выдачи бана часа, UNIX время истечения бана чата и причину выдачи. Они записаны через пробел. UNIX время в обеих случаях приобретает целочисленный тип данных, а вот причина - строковый. Следовательно, выглядеть будет так: dds[100]. 100 я указал для примера. Допустим, максимальная длина причины не должна превышать 100 символов. В целом это будет выглядеть так:

Код: Выделить всё

new argument1, argument2, argument3[100];
sscanf(string, "dds[100]", argument1, argument2, argument3);
Пример 3.
Создаем команду телепортации по указанным координатам. Допустим, координаты записаны через запятую в переменной string. В этом случае наш sscanf примет следующий вид:

Код: Выделить всё

new Float:x, Float:y, Float:z;
sscanf(string, "p<,>fff", x, y, z);
Пример 4.
Ситуация посложнее. В переменную записаны дата и время какого-либо события: "2017-05-25 22:00". Сначала нужно извлечь три аргумента целочисленного типа, записанных через тире, а затем два аргумента целочисленных типов, записанных через двоеточие:

Код: Выделить всё

new argument1, argument2, argument3, argument4, argument5;
sscanf(string, "p<->dddp<:>dd", argument1, argument2, argument3, argument4, argument5);
Ну и тогда в argument1 попадет 2017, в argument 2 - 05, в argument3 - 25, в argument 4 - 22, в аргумент 5 - 00.

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

Код: Выделить всё

if(sscanf(string, "типы данных", argument1, ... argumentn)) return SendClientMessage(playerid, 0xFF0000FF, "Аргументы не найдены."); 
и, соответственно,

Код: Выделить всё

if(!sscanf(string, "типы данных", argument1, ... argumentn)) return SendClientMessage(playerid, 0xFF0000FF, "Аргументы найдены.");
Пример команды /goto. Можно вводить координаты, можно вводить ID игрока, а можно просто ничего не вводить и телепортироваться на заданные кодом координаты:

Код: Выделить всё

CMD:goto(playerid, params[])
{
        if(!strlen(params))//Если пользователь вообще ничего не ввел, телепортируем его по координатам, указанным ниже
            return SetPlayerPos(playerid, ваша_координата_х, ваша_координата_y, ваша_координата_z);
        new Float:x, Float:y, Float:z;//Создаем три новые переменные дробного типа, куда впоследствии запишем координаты игроков
        if(!sscanf(params, "u", params[0]))//Если пользователь ввел одно целое число, скорее всего являющееся идом игрока:
        {
                if(params[0] == INVALID_PLAYER_ID)//Проверяем, в сети ли игрок
                    return SendClientMessage(playerid, 0xFF0000FF, "Указанный вами игрок не в сети");
                GetPlayerPos(params[0], x, y, z);//Получаем позицию указанного игрока
                SetPlayerPos(playerid, x, y, z);//Изменяем позицию нашу на позицию указанного игрока
                return true;
        }
        if(!sscanf(params, "p<,>fff", x, y, z)//Проверяем, найдены ли три координаты дробного типа, записанные через запятую, в строке
                return SetPlayerPos(playerid, x, y, z);//Если найдены, телепортируем на них игрока
        return true;
}
Собственно это все.
Автор: Elrmrnt-Kritik

Ответить