PDA

Просмотр полной версии : [Function] nstrval



KrutoyKrosch
17.01.2017, 13:25
Описание:

Стандартная функция strval возвращает 0 когда в нее поступила строка без числа, и так же она возвращает 0 если в нее поступила строка с числом 0.

Поэтому это небольшой FIX этой функции, который добавит отдельный параметр для числа.

Возвращает:


0 - удачно выполнилась
1 - в строке нету числа

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


new val;

if(!nstrval("21", val))
printf("Val %d", val);
else
print("Error");


Сама функция (в конец кода):



stock nstrval(string[], &val)
{
val = strval(string);
return !val && string[0] != '0';
}


Автор: _KROSCH

Спасибо Daniel_Cortez за идею.

Nexius_Tailer
17.01.2017, 13:28
Функция не учитывает строки, которые не пусты, но при этом никакой цифры в себе не имеют. Лучше будет просто делать проверку через "IsNumeric"

KrutoyKrosch
17.01.2017, 13:35
Не понял тебя...

https://pp.vk.me/c638126/v638126947/1a960/fmMXoB6UDWk.jpg

https://pp.vk.me/c638126/v638126947/1a968/44X5exdyaWU.jpg

https://pp.vk.me/c638126/v638126947/1a970/kJGIq2hjSUk.jpg

Nexius_Tailer
17.01.2017, 13:48
Немного не так прочитал проверку "string[0] != '0';" (сначала показалось, что тут проверка на завершающий символ xD)

Но тогда возникает другая проблема. Вот в такой строке:

new string[] = "_0"; //Или любой другой знак в нулевой ячейке, но кроме цифр
Сама функция вернёт 1 (неудачно), а число в строке есть и обычный strval его на самом деле видит.

KrutoyKrosch
17.01.2017, 13:53
Видит? Точно? А почему же тогда 0 выводит? Если бы она его видела вернуло бы 1 и далее вывело то число

https://pp.vk.me/c638126/v638126947/1a97b/LwBCuw3jt2Y.jpg

Тем более вчитайся в return, там же стоит проверка что strval 0 вернула

PS. Побаловался, с русскими символами только реагирует на число в таком случае (если число среди символов), но и то возвращает 0

Nexius_Tailer
17.01.2017, 14:06
Хм, значит всё-же хорошая реализация.
Что-то мне казалось, что strval не только конкретные вырезки строки с числом преобразовывать умеет, потому подумал, что вариант с проверкой только нулевой ячейки ненадёжен

ziggi
17.01.2017, 15:59
Почему при успешном выполнении возвращается 0, а не 1?

KrutoyKrosch
17.01.2017, 16:30
Почему при успешном выполнении возвращается 0, а не 1?

Если честно, то мне чот влом было переделать условие так, что бы оно 1 возвращало и работало правильно)0))

Если немного соврать, а чем я хуже создателя strcmp?

$continue$
17.01.2017, 17:36
Убейте меня, но я не могу жить без костылей.



#if !defined isnull
#define isnull(%1) \
(((%1[0]) == 0) || ((%1[0]) == '\1') && ((%1[1]) == 0))
#endif

#if !defined NaN
#define NaN floatsqroot(-1)
#endif
stock Float: fix__strval(const str[])
{
if(isnull(str))
return NaN;
else if (str[0] >= '0' && str[0] <= '9' || strval(str) < 0)
return float(strval(str));
else
return NaN;
}
#if defined _ALS_fix_strval
#undef strval
#else
#define _ALS_fix_strval
#endif
#define strval fix__strval


Возвращаемые значение:
NaN - пустая строка либо введены не цифры.
Если число введено нормально - вернуть его.

Nexius_Tailer
17.01.2017, 17:37
Если честно, то мне чот влом было переделать условие так, что бы оно 1 возвращало и работало правильно)0))

Если немного соврать, а чем я хуже создателя strcmp?
strcmp может возвращать помимо нуля ещё как минимум 1 или -1. Такие значения указывают на конкретные различия, что-то вроде того, сколько символов в строках не совпало

Вот вариант для ленивых, как сделать так, чтобы при успехе возвращало 1 и при неудаче 0:

stock nstrval(string[], &val)
{
val = strval(string);
return !(!val && string[0] != '0');
}

VVWVV
17.01.2017, 17:39
Если честно, то мне чот влом было переделать условие так, что бы оно 1 возвращало и работало правильно)0))

Если немного соврать, а чем я хуже создателя strcmp?

Тем, что возвращаемое значение в strcmp имеет смысл:


0 if strings match each other on given length;
1 o r -1 if some character do not match: string1[i] - string2[i] ('i' represents character index starting from 0);
difference in number of characters if one string matches only part of another string.



Убейте меня, но я не могу жить без костылей.



#if !defined isnull
#define isnull(%1) \
(((%1[0]) == 0) || ((%1[0]) == '\1') && ((%1[1]) == 0))
#endif

#if !defined NaN
#define NaN floatsqroot(-1)
#endif
stock Float: fix__strval(const str[])
{
if(isnull(str))
return NaN;
else if (str[0] >= '0' && str[0] <= '9' || strval(str) < 0)
return float(strval(str));
else
return NaN;
}
#if defined _ALS_fix_strval
#undef strval
#else
#define _ALS_fix_strval
#endif
#define strval fix__strval


Возвращаемые значение:
NaN - пустая строка либо введены не цифры.
Если число введено нормально - вернуть его.

Минус данного подхода заключается в том, что всегда придётся использовать тег Float, иначе будут предупреждения и другие результаты.

KrutoyKrosch
17.01.2017, 17:46
strcmp может возвращать помимо нуля ещё как минимум 1 или -1. Такие значения указывают на конкретные различия, что-то вроде того, сколько символов в строках не совпало

Вот вариант для ленивых, как сделать так, чтобы при успехе возвращало 1 и при неудаче 0:

stock nstrval(string[], &val)
{
val = strval(string);
return !(!val && string[0] != '0');
}

точна, скобочки, совсем забыл что можно их использовать было

$continue$
17.01.2017, 18:01
Я же сразу сказал, что это костыль, но он хотя бы логичный. Так как возвращает число, которое пользователь не введет. По свойству NaN не равняться не какому другому числу, даже самому себе. Есть лучше варианты? Возвращать число в диапазоне INT_MIN до INT_MAX - не лучшая идея. Все же их пользователь сможет вполне ввести. На счет тэга:


new integer = floatround(strval(str));


Только float использовать для сравнение, что функция выполнилась не удачна (введены буквы, строка пустая)

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


Минус данного подхода заключается в том, что всегда придётся использовать тег Float, иначе будут предупреждения и другие результаты.

P.S: автор сделай перехват нативки, хотя и изменение работы самой функции не лучшая практика в перехватах, но я думаю, что тут есть место быть перехватам.

ziggi
17.01.2017, 18:02
Или так:
val || string[0] == '0';

VVWVV
17.01.2017, 18:13
P.S: автор сделай перехват нативки, хотя и изменение работы самой функции не лучшая практика в перехватах, но я думаю, что тут есть место быть перехватам.

Очень плохая идея, так как изменяется логика функции.

KrutoyKrosch
17.01.2017, 18:19
У меня же аргумент там дополнительный...

$continue$
17.01.2017, 18:23
Я всего лишь предложил, НО перед этим предупредил, что это не самая лучшая идея и я считаю, что это, что то вроде исключения из правил. Как минимум в strval баг и это один из вариантов его пофиксить, то почему бы и нет?

У меня же аргумент там дополнительный...

KrutoyKrosch
17.01.2017, 18:33
Ну харашо харашо

Версия 0.2

Изменения:



Мы пошли на отчаянный для нас шаг и переделали возвращаемые значение, теперь они возвращаю это:

0 - функция не выполнилась (человекообразное существо обнаглело и решило обхитрить систему введя символы)
1 - функция выполнилась, "тут я хотел пошутить, но думаю забанят"

И самое главное изменение: теперь ленивым (на подобии меня) не надо будет прописывать везде nstrlen, компилятор это сделает за вас.



stock nstrval(string[], &val)
{
val = strval(string);
return !(!val && string[0] != '0');
}
#if defined _ALS_strval
#undef strval
#else
#define _ALS_strval
#endif
#define strval nstrval

VVWVV
17.01.2017, 18:59
А теперь читаем:


Перехватчик не должен менять аргументы перехватываемой функции, её логику работы и предназначение.
Изменение возвращаемых значений допускается только в том случае, если это не нарушает совместимости с оригинальной функцией.
Например, в античите на HP перехватчик GetPlayerHealth возвращает не то значение, которое возвратит оригинальная функция, а кол-во HP игрока, хранящееся в античите. Но в то же время перехватчик должен возвращать именно HP, а не сумму HP и брони или ещё что-нибудь, что поменяет логику работы функции.
То же самое относится к изменению аргументов функции. Если с помощью перехвата добавить в какую-либо функцию дополнительные параметры, а потом убрать перехватчик, то компилятор будет выдавать ошибки и код не будет компилироваться без перехватчика, т.к. в оригинальной функции тех дополнительных параметров нет.
Иными словами, работа перехватчика должна быть незаметной для того кода, который использует перехватываемую функцию, как будто того перехватчика и нет.
Если же вам нужна функция, работающая по-другому - сделайте отдельную функцию, но не нужно путать её с оригиналом с помощью перехвата. Вмешательство в стандартную логику обычно приводит только к проблемам.

KrutoyKrosch
17.01.2017, 19:04
Я иду против системы, поэтому нормальна

DeimoS
17.01.2017, 22:54
Вставь твой фикс в любой скрипт, где использовалась стандартная strval и компилятор выплюнет ошибку (одна из причин, по которой не стоит менять логику стандартных функций).
Да и не всегда требуется проверка того, вёл ли игрок число. Это может быть заранее известно (если информация, например, не игроком вводилась).

Для подобных случаев гораздо проще использовать sscanf:

new string[] = "AZAZA 123",
value;
sscanf(string, "I(-1)", value);
if(value == -1)
return;
Естественно "-1" нужно заменять на подходящее по случаю значение (то, которое игрок не может ввести)

KrutoyKrosch
17.01.2017, 23:39
Что бы еще выслушивать "А у меня sscanf НЕ ЗАПУСКАЕТСЯ !11!11 Error 19"? Спасибо, мне за сегодня хватило.

DeimoS
18.01.2017, 01:54
Так я и не говорил писать функцию с использованием sscanf. Я говорил, что вместо подобных фиксов гораздо логичнее использовать именно sscanf, а не создавать в скрипте 1000 функций с одинаковым предназначением. И делать проверки только там, где это действительно требуется, а не везде.

Твой перехват, например, будет проверять и такую строку

strval("155")
Хотя ещё на этапе компиляции известно, что там число.

vovandolg
20.01.2017, 21:25
По моему sscanf сейчас такой же актуальный и стабильный плагин/дополнение как стример и движки dc_cmd, pawn.cmd и т.п.
Зачем делать то что уже придумано))

Daniel_Cortez
20.01.2017, 22:38
Во-первых, что означает "n" в названии "nstrval"? Хотелось бы знать, какой логикой вы руководствовались, когда выбирали название (если она вообще имела место).
Во-вторых, функция возвращает 0, что означает ошибку, если подать на вход строку " 0" (с пробелом), хотя остальные строки с пробелами в начале вполне нормально считываются. Так и задумано?
Та же самая ошибка проявится, если ввести абсолютно правильные (https://github.com/compuphase/pawn/blob/6de1822ac1625451bf151159bb0178c09f087bea/amx/amxstring.c#L605) значения "-0" и "+0".
В-третьих, само по себе выражение "!(!val && string[0] != '0')" неэффективно, т.к. если значение в val будет ненулевым, всё равно будет проверена ячейка string[0].
К слову, ziggi уже предложил нормальный вариант в этой теме.
В-четвёртых, зачем вообще городить подобные костыли, когда, как правильно заметили другие в этой теме, уже давно есть плагин sscanf2? Сейчас он используется почти в каждом моде, кроме разве что вшивых RLS, доисторических GF и поделиях таких "профессионалов", которым либо незнание, либо религия не позволяет использовать плагины.

Что бы еще выслушивать "А у меня sscanf НЕ ЗАПУСКАЕТСЯ !11!11 Error 19"? Спасибо, мне за сегодня хватило.
Это уже проблемы неосиляторов.

Nexius_Tailer
21.01.2017, 18:28
Сейчас он используется почти в каждом моде, кроме разве что вшивых RLS, доисторических GF и поделиях таких "профессионалов", которым либо незнание, либо религия не позволяет использовать плагины.
Ну а вот я вижу много примеров, когда люди, написав некий fs/include, требуют подключения какого-либо плагина/другого инклуда, который в свою очередь требует третий. Это далеко не всегда удобно, особенно когда в своём скрипте никакие "вложенные" зависимости не используются

Daniel_Cortez
22.01.2017, 12:32
Ну а вот я вижу много примеров, когда люди, написав некий fs/include, требуют подключения какого-либо плагина/другого инклуда, который в свою очередь требует третий. Это далеко не всегда удобно, особенно когда в своём скрипте никакие "вложенные" зависимости не используются
Можно подумать, sscanf2 - такая неподъёмная зависимость... -_-
На деле он уже есть на многих серверах (если не считать за "многие" RLS и всю ту нечисть, что я упомянул в посте выше), не говоря уже о том, что сам плагин никаких третьих зависимостей не требует.
Изобрести велосипед ты всегда успеешь - другое дело найти разумный компромисс между функционалом и зависимостями, не подводя все плагины/инклуды под одну кальку.