[Include] Dynamic String Splitter [Enumerator Functions Included!]
#1

Dynamic String Splitter

Description

This include will facilitate the operation of splitting strings, in a dynamic way. This include generated from the fact of wanting a complete dynamic system, but at the end, this is what came out of it:

PHP код:
sscanf(string_to_split"p<|>iiiiiiiiiiiiiiiiiiii"aInventory[playerid][0][inventory_item_id], aInventory[playerid][0][inventory_item_extra], aInventory[playerid][1][inventory_item_id], aInventory[playerid][1][inventory_item_extra], aInventory[playerid][2][inventory_item_id], aInventory[playerid][2][inventory_item_extra], aInventory[playerid][3][inventory_item_id], aInventory[playerid][3][inventory_item_extra], aInventory[playerid][4][inventory_item_id], aInventory[playerid][4][inventory_item_extra], aInventory[playerid][5][inventory_item_id], aInventory[playerid][5][inventory_item_extra], aInventory[playerid][6][inventory_item_id], aInventory[playerid][6][inventory_item_extra], aInventory[playerid][7][inventory_item_id], aInventory[playerid][7][inventory_item_extra], aInventory[playerid][8][inventory_item_id], aInventory[playerid][8][inventory_item_extra], aInventory[playerid][9][inventory_item_id], aInventory[playerid][9][inventory_item_extra]); 
The code above is obviously not dynamic. But with this include, that becomes (which is dynamic):

PHP код:
new sscanf_format[30];
SplitIntegers_IndexesEnum(string_to_split"|"aInventory[playerid], "ii""ii"sscanf_format); 
Test code (simulating what's above):

PHP код:
new string_to_split[] = "5|2|3|5|7|8|2|2|3|4|5|6|77|12|1|2|55|2|3|8"sscanf_format[30];
enum eInventory
{
    
inventory_item_id,
    
inventory_item_extra
};
new 
aInventory[MAX_PLAYERS][10][eInventory];
SplitIntegers_IndexesEnum(string_to_split"|"aInventory[0], "ii""ii"sscanf_format);
for(new 
0sizeof(aInventory[]); ++)
{
    for(new 
0_:eInventory++)
    {
        
printf("i: %d, j: %d - %d"ijaInventory[0][i][eInventory:j]);
    }

In case your enumerator has elements in between (for this example, let's put one element in between the enumerator that we used previously - note that "ii" in the example above changes to "i-ii"), you can do:

PHP код:
new string_to_split[] = "5|2|3|5|7|8|2|2|3|4|5|6|77|12|1|2|55|2|3|8"sscanf_format[32];
enum eInventory
{
    
inventory_item_id,
    
inventory_item_extra_1,
    
inventory_item_extra_2
};
new 
aInventory[MAX_PLAYERS][10][eInventory];
SplitIntegers_IndexesEnum(string_to_split"|"aInventory[0], "i-ii""ii"sscanf_format);
for(new 
0sizeof(aInventory[]); ++)
{
    for(new 
0_:eInventory++)
    {
        
printf("i: %d, j: %d - %d"ijaInventory[0][i][eInventory:j]);
    }

That's just one example, and the use of one function in this include. It has many other uses and plenty more useful functions.

The example script (dynamic_string_splitter_example.pwn) and the include (dynamic_string_splitter.inc) requires: Download

https://github.com/Kevin-Reinke/Dynamic_String_Splitter
Reply
#2

Good job!
Reply
#3

You made it a bit confusing in the topic... I was thinking total disaster until I looked at the code.

Post a list of the functions.

Awesome job, makes sscanf newbs' jobs a bit easier. Not that I think it should be any easier as a single sscanf statement, but yeah.
Reply
#4

Erm what?
I understand this is created for newbies, but give me a good reason why they shouldn't learn doing something like this?
PHP код:
sscanf(item_info"p<|>a<ii>["#MAX_INVENTORY_ITEMS"]", aInventory[playerid]); 
*Note: that exact code might not work (probably will tho) since I wrote it here, but yeah, you actually can use powerful features of sscanf like enum and arrays to do these for you.
Reply
#5

Sweet.
Reply
#6

Keep up the good work!
Reply
#7

I tried out the example you posted here, and it doesn't work the way you said it would.

Код:
public OnGameModeInit()
{
	new
		playerid,
		testid = 5,
		item_info[] = "1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20"
	;
	
	sscanf(item_info, "p<|>iiiiiiiiiiiiiiiiiiii", aInventory[playerid][0][inventory_item_id], aInventory[playerid][0][inventory_item_extra], aInventory[playerid][1][inventory_item_id], aInventory[playerid][1][inventory_item_extra], aInventory[playerid][2][inventory_item_id], aInventory[playerid][2][inventory_item_extra], aInventory[playerid][3][inventory_item_id], aInventory[playerid][3][inventory_item_extra], aInventory[playerid][4][inventory_item_id], aInventory[playerid][4][inventory_item_extra], aInventory[playerid][5][inventory_item_id], aInventory[playerid][5][inventory_item_extra], aInventory[playerid][6][inventory_item_id], aInventory[playerid][6][inventory_item_extra], aInventory[playerid][7][inventory_item_id], aInventory[playerid][7][inventory_item_extra], aInventory[playerid][8][inventory_item_id], aInventory[playerid][8][inventory_item_extra], aInventory[playerid][9][inventory_item_id], aInventory[playerid][9][inventory_item_extra]);
	printf("%i %i|%i\n", testid, aInventory[playerid][testid][inventory_item_id], aInventory[playerid][testid][inventory_item_extra]);

	new integers[MAX_INV_ITEMS], count[2];
	for(new i = 0, j = split_integers(item_info, "|", integers); i < j; i += sizeof(aInventory[][]))
	{
		for(new k = 0; k < sizeof(aInventory[][]); k ++)
		{
			aInventory[playerid][count[0]][eInventory:k] = integers[count[1] ++];
		}

		count[0] ++;
	}
	
	printf("%i %i|%i", testid, aInventory[playerid][testid][inventory_item_id], aInventory[playerid][testid][inventory_item_extra]);
	return 1;
}
Second one goes beyond the MAX_INV_ITEMS (10) array index.

I re-wrote the code, and it should work:
Код:
new integers[MAX_INV_ITEMS*2], count, limit = sizeof (aInventory[])/2;
for (new i, k, j = split_integers(item_info, "|", integers); i < j; i++)
{
    for (k = 0; k < sizeof (aInventory[][]); k++) // I removed "new" and added it to the main loop too, because it's better for optimization. (Creating stuff in loops = bad idea)
    {
		aInventory[playerid][count][eInventory: k] = integers[count+k];
    }
    count++;

    if (count == limit)
        break;
}
Anyway, good job!


EDIT:

I suggest optimizing the code a bit.
For example, instead of looping and replacing, you should take advantage of sscanf's amazing speed.

Код:
stock split_integers(string_to_split[], const separator[], integers[])
{
	new _format[20], count = 1;
	for(new i = 0, j = strlen(string_to_split); i <= j; i ++)
	{
		if(string_to_split[i] == separator[0])
		{
			string_to_split[i] = ' ';
			count ++;
		}
	}

	format(_format, sizeof(_format), "a<i>[%d]", count);

	sscanf(string_to_split, _format, integers);
	return count;
}
You should add an extra parameter called "size", with a default value of "sizeof (integers))"
Not only does it remove the need for looping, but it also limits error (If the array in sscanf is bigger than "integers[]" for example)

Код:
stock split_integers(string_to_split[], const separator[], integers[], size = sizeof (integers))
{
	new _format[21];
	format(_format, sizeof(_format), "p<%c>a<i>[%d]", separator[0], size);

	sscanf(string_to_split, _format, integers);
	return size;
}
But anyway, great job!
Reply
#8

What I wanted to achieve with this include wasn't really as expected, but it's still functional. I didn't want that loop there in the first place. I'll update it when I find the time.

Thanks for the replies, I'll check them out and reply to them when the include is updated.
Reply
#9

Good job !
Reply
#10

Alright, so the include has been updated! It has completely new functions in addition to newly introduced string-related functions and global no-data-type-specific functions (therefore, I don't feel the need in replying to the replies above), that are vastly better and more useful (since the initial attempt ended up having to use ugly loops outside the functions, not to mention the loop inside each function to get a count so it could be used in another loop...).

Anyhow, this ugly mess:
PHP код:
new integers[MAX_INV_ITEMS*2], countlimit sizeof (aInventory[])/2;
for (new 
iksplit_integers(item_info"|"integers); ji++)
{
    for (
0sizeof (aInventory[][]); k++) // I removed "new" and added it to the main loop too, because it's better for optimization. (Creating stuff in loops = bad idea)
    
{
        
aInventory[playerid][count][eInventoryk] = integers[count+k];
    }
    
count++;
    if (
count == limit)
        break;

Turns into (which is also a lot more efficient as SSCANF does most of the work now):
PHP код:
new sscanf_format[30]; 
SplitIntegers_IndexesEnum(string_to_split"|"aInventory[playerid], "ii""ii"sscanf_format); 
The best part is that you can specify the amount of cells the functions will build up in order to split strings (think of it as query used in SQL functions, but inverse). Meaning, there's no limit and it will speed up short to long processes (the more cells there are, the longer it takes).

Check out the main post for more information, and for the download link! Don't forget to check out the example file too!

Also, thanks to everyone!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)