AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Scripting Help (https://forums.alliedmods.net/forumdisplay.php?f=11)
-   -   Check character then replace (https://forums.alliedmods.net/showthread.php?t=281525)

Syturi0 04-13-2016 14:32

Check character then replace
 
I want to only allow A-Z, 0-9, and a few special characters like [](),.-~#=+-, on nicknames.

PHP Code:

new const g_AllowNickCharacter [][] =
{
    
"a""b""c""d""e""f""g""h""i",
    
"j""k""l""m""n""o""p""q""r",
    
"s""t""u""v""x""z""<"">"",",
    
"+""*""'""?""="")""(""/""#",
    
".""-"";"":""_""ç""~""",
    
"!""|""\", "[", "]", "1", "2", "3", "4",
    "
5", "6", "7", "8", "9", "0", "@"


If the player uses a character that is not one of those mentioned above, it will get removed.
This is a test i did, its only for the first character:
PHP Code:

public client_infochanged(id)
{
    if(!
is_user_bot(id) && !is_user_hltv(id))
    {
        new const 
name[] = "name"
        
new szNewName[33]
        
get_user_info(idnameszNewNamecharsmax(szNewName))

        for(new 
0sizeof(g_AllowNickCharacter); i++)
            if(!(
equal(szNewName[0], g_AllowNickCharacter[i]) != -1))
                    
replace(szNewNamecharsmax(szNewName), szNewName[0], "")

        
set_user_info(idnameszNewName)
    }


Whats wrong?

siriusmd99 04-13-2016 17:00

Re: Check character then replace
 
It's not 2d array, because you have characters. If you had strings for example instead of "a" you had "alphabeta" then you should use double [][] but here is only [].

PHP Code:

new const g_AllowNickCharacter [] =
{
    
"a""b""c""d""e""f""g""h""i",
    
"j""k""l""m""n""o""p""q""r",
    
"s""t""u""v""x""z""<"">"",",
    
"+""*""'""?""="")""(""/""#",
    
".""-"";"":""_""ç""~""",
    
"!""|""\", "[", "]", "1", "2", "3", "4",
    "
5", "6", "7", "8", "9", "0", "@"



PHP Code:

public client_infochanged(id)
{
    if(!
is_user_bot(id) && !is_user_hltv(id))
    {
        new const 
name[] = "name"
        
new szNewName[33]
        
get_user_info(idnameszNewNamecharsmax(szNewName))

       for(new 
0charsmax(szNewName); i++)
            if(
containi(g_AllowNickCharacter,szNewName[i]) == -1)
                    
replace(szNewNamecharsmax(szNewName), szNewName[i], "")

        
set_user_info(idnameszNewName)
    }


I used containi so that case sensitive works, i mean if you have allowed "a" then "A" will be also allowed.If you do not want that then just change "containi" to "contain".

if(containi(g_AllowNickCharacter,szNewName[i]) == -1)

it means that if current symbol of player's name doesnt exists in allowed constant array then this character will removed with your method.

Syturi0 04-13-2016 17:10

Re: Check character then replace
 
Quote:

Originally Posted by siriusmd99 (Post 2410806)
It's not 2d array, because you have characters. If you had strings for example instead of "a" you had "alphabeta" then you should use double [][] but here is only [].

PHP Code:

new const g_AllowNickCharacter [] =
{
    
"a""b""c""d""e""f""g""h""i",
    
"j""k""l""m""n""o""p""q""r",
    
"s""t""u""v""x""z""<"">"",",
    
"+""*""'""?""="")""(""/""#",
    
".""-"";"":""_""ç""~""",
    
"!""|""\", "[", "]", "1", "2", "3", "4",
    "
5", "6", "7", "8", "9", "0", "@"



PHP Code:

public client_infochanged(id)
{
    if(!
is_user_bot(id) && !is_user_hltv(id))
    {
        new const 
name[] = "name"
        
new szNewName[33]
        
get_user_info(idnameszNewNamecharsmax(szNewName))

       for(new 
0charsmax(szNewName); i++)
            if(
containi(g_AllowNickCharacter,szNewName[i]) == -1)
                    
replace(szNewNamecharsmax(szNewName), szNewName[i], "")

        
set_user_info(idnameszNewName)
    }


I used containi so that case sensitive works, i mean if you have allowed "a" then "A" will be also allowed.If you do not want that then just change "containi" to "contain".

if(containi(g_AllowNickCharacter,szNewName[i]) == -1)

it means that if current symbol of player's name doesnt exists in allowed constant array then this character will removed with your method.

Still not working.

Syturi0 04-19-2016 09:35

Re: Check character then replace
 
bump

Black Rose 04-19-2016 11:25

Re: Check character then replace
 
When using double quotes ( " ), you're basically telling the compiler that it should terminate the string after each quote So the string is actually:
a, null, b, null ...
You should use single quotes ( ' ) for characters.

Code:
    new const g_AllowNickCharacter [] = { "a", "b", "c" }     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]);
Code:

a, a, a
->
Code:
    new const g_AllowNickCharacter [] = { 'a', 'b', 'c' }     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]);
Code:

abc, abc, a


Remember though, you have to terminate the string by putting null at the end or all functions will continue reading memory until it reaches 0, which could cause memory access runtime errors.
Code:
new const g_AllowNickCharacter [] = { 'a', 'b', 'c' } public plugin_init() {     register_plugin("Test Plugin 5", "", "[ --{-@ ]");     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]); }
Code:

abcTest Plugin 5, abcTest Plugin 5, a
->
Code:
new const g_AllowNickCharacter [] = { 'a', 'b', 'c', 0 } public plugin_init() {     register_plugin("Test Plugin 5", "", "[ --{-@ ]");     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]); }
Code:

abc, abc, a
Code:
new const g_AllowNickCharacter [] = {     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',     'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',     's', 't', 'u', 'v', 'x', 'z', '<', '>', ',',     '+', '*', ''', '?', '=', ')', '(', '/', '#',     '.', '-', ';', ':', '_', /* 'ç', */ '~', /*'' ? */     '!', '|', '\', '[', ']', '1', '2', '3', '4',     '5', '6', '7', '8', '9', '0', '@', 0 // <-- Important null to end the string. }
You could just as well do
Code:
new const g_AllowNickCharacter [] = "abcdefghijklmnopqrstuvxz<>,+*'?=)(/#.-;:_~!|\[]1234567890@"



replace() will check for occurances, skip containi() and add upper case letters instead.



With all that said, you should check out an ASCII chart and try using direct character comparisons instead.
For example:
Code:
if ( 'a' <= string[i] <= 'z' )     // ...
And how do we do this the easy way? We sort the string real fast so we can find the combinations easily:
Code:
    new g_AllowNickCharacter [] = "abcdefghijklmnopqrstuvxz<>,+*'?=)(/#.-;:_~!|\[]1234567890@";     server_print("unsorted: %s", g_AllowNickCharacter);     SortIntegers(g_AllowNickCharacter, sizeof g_AllowNickCharacter - 1);     server_print("  sorted: %s", g_AllowNickCharacter);
Code:

unsorted: abcdefghijklmnopqrstuvxz<>,+*'?=)(/#.-;:_~!|\[]1234567890@
  sorted: !#'()*+,-./0123456789:;<=>?@[\]_abcdefghijklmnopqrstuvxz|~

And breaked down, this shows the groupings we can use:
Code:

/*
a-z
A-Z
0-9

!
#
'
()*+,-./
:;<=>?@
[\]
_
|
~
*/

That requires another way of replacing characters but a simple way is just using a buffer since the string is so small.
This way is the most efficient. There are a lot of comparisons, but replace inside a loop is loop inception. Don't get me started on replace_all. loop3
Code:
    new string1[32] = "abcåäöABC¤$123€%!";     new string2[32];     new a;     for ( new i ; i < sizeof string1 ; i++ ) {         if (             'a' <= string1[i] <= 'z' ||             'A' <= string1[i] <= 'Z' ||             '0' <= string1[i] <= '9' ||             string1[i] == '!' ||             string1[i] == '#' ||             string1[i] == '^'' || // ' <- Because the code wrapper on this page uses \ as control character while pawn uses ^             '(' <= string1[i] <= '/' ||             ':' <= string1[i] <= '@' ||             '[' <= string1[i] <= ']' ||             string1[i] == '_' ||             string1[i] == '|' ||             string1[i] == '~'             )             string2[a++] = string1[i];     }     string2[a] = 0; // Don't forget to terminate.     server_print("string1: %s", string1);     server_print("string2: %s", string2);
Code:

string1: abc+Ñ+ñ+ÂABC-ñ$123Ôé¼%!
string2: abcABC123!

Now I know you're asking... "How could I improve this further?".
Well. Comparing a variable 12 times will make it read the value of that variable from the memory 12 times. With a simple switch(), you can reduce that to 1!
Code:
    new string1[32] = "abcåäöABC¤$123€%!";     new string2[32];     new a;     for ( new i ; i < sizeof string1 ; i++ ) {         if ( IsAcceptable(string1[i]) )             string2[a++] = string1[i];     }     string2[a] = 0; // Don't forget to terminate.     server_print("string1: %s", string1);     server_print("string2: %s", string2); } IsAcceptable(c) {     switch (c) {         case 'a' .. 'z' : return 1;         case 'A' .. 'Z' : return 1;         case '0' .. '9' : return 1;         case '!' : return 1;         case '#' : return 1;         case '^'' : return 1; // ' <- Because the code wrapper on this page uses \ as control character while pawn uses ^         case '(' .. '/' : return 1;         case ':' .. '@' : return 1;         case '[' .. ']' : return 1;         case '_' : return 1;         case '|' : return 1;         case '~' : return 1;     }     return 0; }
Code:

string1: abc+Ñ+ñ+ÂABC-ñ$123Ôé¼%!
string2: abcABC123!

Readability could be improved but I guess you get the point and can take necessary parts from these examples that will fit you best.
In the end, none of these methods are slow. There's no need to worry about using one over another.

Syturi0 07-28-2016 00:32

Re: Check character then replace
 
Quote:

Originally Posted by Black Rose (Post 2412329)
When using double quotes ( " ), you're basically telling the compiler that it should terminate the string after each quote So the string is actually:
a, null, b, null ...
You should use single quotes ( ' ) for characters.

Code:
    new const g_AllowNickCharacter [] = { "a", "b", "c" }     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]);
Code:

a, a, a
->
Code:
    new const g_AllowNickCharacter [] = { 'a', 'b', 'c' }     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]);
Code:

abc, abc, a


Remember though, you have to terminate the string by putting null at the end or all functions will continue reading memory until it reaches 0, which could cause memory access runtime errors.
Code:
new const g_AllowNickCharacter [] = { 'a', 'b', 'c' } public plugin_init() {     register_plugin("Test Plugin 5", "", "[ --{-@ ]");     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]); }
Code:

abcTest Plugin 5, abcTest Plugin 5, a
->
Code:
new const g_AllowNickCharacter [] = { 'a', 'b', 'c', 0 } public plugin_init() {     register_plugin("Test Plugin 5", "", "[ --{-@ ]");     server_print("%s, %s, %c", g_AllowNickCharacter, g_AllowNickCharacter[0], g_AllowNickCharacter[0]); }
Code:

abc, abc, a
Code:
new const g_AllowNickCharacter [] = {     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',     'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',     's', 't', 'u', 'v', 'x', 'z', '<', '>', ',',     '+', '*', ''', '?', '=', ')', '(', '/', '#',     '.', '-', ';', ':', '_', /* 'ç', */ '~', /*'' ? */     '!', '|', '\', '[', ']', '1', '2', '3', '4',     '5', '6', '7', '8', '9', '0', '@', 0 // <-- Important null to end the string. }
You could just as well do
Code:
new const g_AllowNickCharacter [] = "abcdefghijklmnopqrstuvxz<>,+*'?=)(/#.-;:_~!|\[]1234567890@"



replace() will check for occurances, skip containi() and add upper case letters instead.



With all that said, you should check out an ASCII chart and try using direct character comparisons instead.
For example:
Code:
if ( 'a' <= string[i] <= 'z' )     // ...
And how do we do this the easy way? We sort the string real fast so we can find the combinations easily:
Code:
    new g_AllowNickCharacter [] = "abcdefghijklmnopqrstuvxz<>,+*'?=)(/#.-;:_~!|\[]1234567890@";     server_print("unsorted: %s", g_AllowNickCharacter);     SortIntegers(g_AllowNickCharacter, sizeof g_AllowNickCharacter - 1);     server_print("  sorted: %s", g_AllowNickCharacter);
Code:

unsorted: abcdefghijklmnopqrstuvxz<>,+*'?=)(/#.-;:_~!|\[]1234567890@
  sorted: !#'()*+,-./0123456789:;<=>?@[\]_abcdefghijklmnopqrstuvxz|~

And breaked down, this shows the groupings we can use:
Code:

/*
a-z
A-Z
0-9

!
#
'
()*+,-./
:;<=>?@
[\]
_
|
~
*/

That requires another way of replacing characters but a simple way is just using a buffer since the string is so small.
This way is the most efficient. There are a lot of comparisons, but replace inside a loop is loop inception. Don't get me started on replace_all. loop3
Code:
    new string1[32] = "abcåäöABC¤$123€%!";     new string2[32];     new a;     for ( new i ; i < sizeof string1 ; i++ ) {         if (             'a' <= string1[i] <= 'z' ||             'A' <= string1[i] <= 'Z' ||             '0' <= string1[i] <= '9' ||             string1[i] == '!' ||             string1[i] == '#' ||             string1[i] == '^'' || // ' <- Because the code wrapper on this page uses \ as control character while pawn uses ^             '(' <= string1[i] <= '/' ||             ':' <= string1[i] <= '@' ||             '[' <= string1[i] <= ']' ||             string1[i] == '_' ||             string1[i] == '|' ||             string1[i] == '~'             )             string2[a++] = string1[i];     }     string2[a] = 0; // Don't forget to terminate.     server_print("string1: %s", string1);     server_print("string2: %s", string2);
Code:

string1: abc+Ñ+ñ+ÂABC-ñ$123Ôé¼%!
string2: abcABC123!

Now I know you're asking... "How could I improve this further?".
Well. Comparing a variable 12 times will make it read the value of that variable from the memory 12 times. With a simple switch(), you can reduce that to 1!
Code:
    new string1[32] = "abcåäöABC¤$123€%!";     new string2[32];     new a;     for ( new i ; i < sizeof string1 ; i++ ) {         if ( IsAcceptable(string1[i]) )             string2[a++] = string1[i];     }     string2[a] = 0; // Don't forget to terminate.     server_print("string1: %s", string1);     server_print("string2: %s", string2); } IsAcceptable(c) {     switch (c) {         case 'a' .. 'z' : return 1;         case 'A' .. 'Z' : return 1;         case '0' .. '9' : return 1;         case '!' : return 1;         case '#' : return 1;         case '^'' : return 1; // ' <- Because the code wrapper on this page uses \ as control character while pawn uses ^         case '(' .. '/' : return 1;         case ':' .. '@' : return 1;         case '[' .. ']' : return 1;         case '_' : return 1;         case '|' : return 1;         case '~' : return 1;     }     return 0; }
Code:

string1: abc+Ñ+ñ+ÂABC-ñ$123Ôé¼%!
string2: abcABC123!

Readability could be improved but I guess you get the point and can take necessary parts from these examples that will fit you best.
In the end, none of these methods are slow. There's no need to worry about using one over another.

Hi there, sorry for the huge delay, i have been really busy lately.
Thank you for your detailed answer, it works correctly.

PS: You forgot to add
PHP Code:

case ' ' : return 

(space bar)

siriusmd99 07-28-2016 03:16

Re: Check character then replace
 
Why checking all allowed symbols if you can check only symbols which are not allowed?

PHP Code:


//How to use function

if( FixedName(szPlayerName) )
set_user_info(id"name"szPlayerName //If name has been changed it means that it contained restricted symbols and we set new name

FixedName str[] ) 
{
    new 
len strlen(str)
    new 
oldlen len;
    new 
ijtmp;

    while(
len)
    {
       
tmp str[i];
       if( 
tmp 31 && tmp 127)
       {
           switch(
tmp)
           {
               case 
34,36,38,94,96,123,125 : {} //If symbol is restricted then do nothing (to go to the removal part)
               
default : 
               {  
                    
i++;
                    continue; 
//If current symbol is ok then we go to the next one
               
}

           }
       }
       
       
//Code down is executed when current symbol is detected as restricted.
       //This is character's removal part

       
for(ilenj++)
       {
            
str[j] = str[j+1];   //Moving symbols with one step back.
       
}
       
       
len--; //Saving new length

    
}
    
    if(
oldlen != len)
    {
        return 
1;
    }
    
    return 
0;



addons_zz 07-28-2016 21:32

Re: Check character then replace
 
Quote:

Originally Posted by siriusmd99 (Post 2440145)
Why checking all allowed symbols if you can check only symbols which are not allowed?

PHP Code:


//How to use function

if( FixedName(szPlayerName) )
set_user_info(id"name"szPlayerName //If name has been changed it means that it contained restricted symbols and we set new name

FixedName str[] ) 
{
    new 
len strlen(str)
    new 
oldlen len;
    new 
ijtmp;

    while(
len)
    {
       
tmp str[i];
       if( 
tmp 31 && tmp 127)
       {
           switch(
tmp)
           {
               case 
34,36,38,94,96,123,125 : {} //If symbol is restricted then do nothing (to go to the removal part)
               
default : 
               {  
                    
i++;
                    continue; 
//If current symbol is ok then we go to the next one
               
}

           }
       }
       
       
//Code down is executed when current symbol is detected as restricted.
       //This is character's removal part

       
for(ilenj++)
       {
            
str[j] = str[j+1];   //Moving symbols with one step back.
       
}
       
       
len--; //Saving new length

    
}
    
    if(
oldlen != len)
    {
        return 
1;
    }
    
    return 
0;



This is a bad thing to do, an loop inside a loop always shifting everything:
Code:
       for(j = i; j < len; j++)        {             str[j] = str[j+1];   //Moving symbols with one step back.        }

Also, do not hard code chars:
Code:
               case 34,36,38,94,96,123,125 : {} //If symbol is restricted then do nothing (to go to the removal part)
-->
Code:
               case '%',"$', etc...: {} //If symbol is restricted then do nothing (to go to the removal part)
And to do a favor to other when writing code, take some time to name the variables.
Code:
    new i, j, tmp;
-->
Code:
    new latestIndex, currentIndex, currentChar;

@Black Rose solves well the problem, if you want to invert things, do it over his algorithm inverting its logic.
However, the performance on this case is kinda irrelevant whether you check the allowed symbols or the not allowed symbols.

Syturi0 07-28-2016 22:21

Re: Check character then replace
 
Quote:

Originally Posted by siriusmd99 (Post 2440145)
Why checking all allowed symbols if you can check only symbols which are not allowed?

Because i dont know ALL the non-allowed symbols... Like i said, i only want to allow a-z, A-Z, 0-9, and a few normal symbols for example: #_:=-



There are way to many:
http://image.prntscr.com/image/676b4...13c69876f7.png




Anyways the @Black Rose method works perfectly, its exactly what i wanted.


All times are GMT -4. The time now is 18:36.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.