SAMP/sscanf

Материал из Wiki.Pawno-Info.Ru
Перейти к навигации Перейти к поиску
Плагин sscanf от автора Y_Less. Скачать актуальную версию плагина можно из раздела ресурсов.

Описание: данный плагин позволяет "парсить" строку, вычленяя аргументы для требуемых параметров. Работает как с текстовыми файлами, так и с введённой строкой напрямую.

Wiki quote.png

Цитата

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

— Написано Y_Less [Источник: документация по плагину]


Wiki tip.png

Подсказка

Для использования добавьте в мод подключение инклюда:
#include <sscanf2>

Для подключения плагина к серверу на платформе с операционной системой Windows добавляем в конфигурационный файл server.cfg следующую строчку:
plugins sscanf

На *nix-подобных (Ubuntu, CentOS, Linux) системах необходимо дописывать расширение файла, поэтому пишем:
plugins sscanf.so


Wiki note.png

Примечание

Не будет ошибкой указывать расширение файлов плагинов на платформе Windows. Так тоже будет работать:
plugins sscanf.dll


Wiki quote.png

Цитата

Новый инклюд определяет старую версию плагина и выдаёт ошибку.

— Написано Y_Less [Источник: документация по плагину]


Wiki note.png

Примечание

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


Примеры использования

В общем виде код выглядит примерно так:

if(sscanf(params, "ui", giveplayerid, amount))
{
	return SendClientMessage(playerid, 0xFF0000AA, "Синтаксис: /givecash [playerid/name] [amount]");
}

Однако следует отметить, что sscanf можно использовать для любой обработки текста, которую вы хотите. Например, ini-процессор может выглядеть так:

if(sscanf(szFileLine, "p<=>s[8]s[32]", szIniName, szIniValue))
{
	printf("Invalid INI format line");
}


Wiki note.png

Примечание

Существует также альтернативное имя функции sscanf, чтобы избежать путаницы со стандартным sscanf в языке "C" - unformat.
if(unformat(params, "ui", giveplayerid, amount))
{
	return SendClientMessage(playerid, 0xFF0000AA, "Usage: /givecash <playerid/name> <amount>");
}

Спецификаторы

Базовые спецификаторы (примеры использования букв u, i, s и других можно увидеть в коде выше). В таблице представлен расширенный спектр поддерживаемых спецификаторов.

Спецификатор(ы) Формат Примеры значений
i, d Целое число 1, 42, -10
c Символ a, o, *
l Логическое (булево) true, false
b Бинарное 01001, 0b1100
h, x Шестнадцатеричное 1A, 0x23
o Восьмеричное 045,12
n Десятичное 42, 0b010, 0xAC, 045
f Дробное (с плавающей точкой) 0.7, -99.5
g Дробное (стандарт IEEE[1]) 0.7, -99.5, INFINITY, -INFINITY, NAN, NAN_E
u Имя игрока/id (боты или игроки) Y_Less, 0
q Имя бота/id ShopBot, 27
r Имя игрока/id Y_Less, 42
m Цвет {FF00AA}, 0xFFFFFFFF, 444

[1] IEEE (Институт инженеров электротехники и электроники) — международная некоммерческая ассоциация специалистов в области техники, мировой лидер в области разработки стандартов по радиоэлектронике, электротехнике и аппаратному обеспечению вычислительных систем и сетей.

Строки

Как и раньше, спецификатор s используется для указания типа данных, извлекаемых из строки, но теперь работThe specifier s is used, as before, for strings - but they are now more advanced. As before they support collection, so doing:

sscanf("hello 27", "si", str, val);

Выдаст:

hello
27

Код:

sscanf("hello there 27", "si", str, val);

Не сработает, потому что "there" не является числом. В данном случае код должен выглядеть так:

sscanf("hello there", "s", str);

Выдаст:

hello there

Поскольку в спецификаторе после s ничего нет, выдаёт всю строку. Чтобы избежать этого (ровно как и в ситуации, когда надо вывести строку до первого пробела), просто добавьте пробел:

sscanf("hello there", "s ", str);

Will give: Выдаст:

hello

Вы также можете экранировать части строк при помощи \\

sscanf("hello\\ there 27", "si", str, val);

Выдаст:

hello there
27

Wiki note.png

Примечание

Экранирование указывается при помощи двух обратных косых черты (бэк-слешей), поскольку 1 используется компилятором.

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

new str[32], val;
sscanf("hello\\ there 27", "s[32]i", str, val);

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

#define STR_SIZE 32
new str[STR_SIZE], val;
sscanf("hello\\ there 27", "s[" #STR_SIZE "]i", str, val);


Wiki tip.png

Подсказка

Рекомендовано использовать [*] для передачи длины строки в качестве дополнительного параметра (смотри раздел «Предоставленные длины» ниже). В этом случае, когда вы меняете размер строки, вам не нужно менять свои спецификаторы.

Упакованные строки

Данный вид спецификаторов обозначается литерами z, Z и возвращает упакованные строки. В остальном он идентичен s и S, документация по которым была выше.

Массивы

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

new arr[5];
sscanf("1 2 3 4 5", "a<i>[5]", arr);

За спецификатором a сразу следует один тип, заключенный в угловые скобки - этот тип может быть любым из основных типов, перечисленных выше. За ним, как и в случае со строками, следует размер массива. Приведенный выше код поместит числа от 1 до 5 в 5 индексов переменной массива arr.

Wiki note important.png

Важное
примечание

В связи с особенностью обработки индексов массива, для распределения параметров из строки (обычно с командными процессорами используется params) необходимо создавать отдельные переменные непосредственно перед парсингом.
if(!strcmp(cmdtext, "/slap", true))
{
	new targetid, reason[32];
	if(sscanf(cmdtext, "ds", targetid, reason)) return SendClientMessage(playerid, -1, "Синтаксис: /slap [id] [причина]");
	// действие команды
	new string[144];
	format(string, sizeof(string), "Вас ударили по причине: %s", reason);
	SendClientMessage(targetid, -1, string);
	return 1;
}