Official Soldat Forums
Server Talk => Scripting Releases => Topic started by: DorkeyDear on August 10, 2009, 12:22:49 pm
-
Script Name: Explode
Script Description A faster version of Split, aka XSplit
Authors: DorkeyDear (http://soldatcentral.com/index.php?page=profile&u=4), CurryWurst (http://forums.soldat.pl/index.php?action=profile;u=10539)
Core Version: 2.6.5
Full Description:
After redoing my most recent Explode, CurryWurst and I made it much faster being over twice as fast as before!
Included is test code compared to my older version of Explode, with step by step modifications.
More statical numbers are available on Soldat Forums (http://forums.soldat.pl/index.php?topic=27844) including the older XSplit.
function Explode(Source: string; const Delimiter: string): array of string;
var
Position, DelLength, ResLength: integer;
begin
DelLength := Length(Delimiter);
Source := Source + Delimiter;
repeat
Position := Pos(Delimiter, Source);
SetArrayLength(Result, ResLength + 1);
Result[ResLength] := Copy(Source, 1, Position - 1);
ResLength := ResLength + 1;
Delete(Source, 1, Position + DelLength - 1);
until (Position = 0);
SetArrayLength(Result, ResLength - 1);
end;
CurryWurst and I derived this with much experimentation.
function Explode(Source: string; const Delimiter: string): array of string;
var
Position, DelLength, ResLength, CurResLength: integer;
begin
DelLength := Length(Delimiter);
Source := Source + Delimiter;
CurResLength := 1;
SetArrayLength(Result, 1);
repeat
Position := Pos(Delimiter, Source);
if (CurResLength = ResLength) then begin
CurResLength := 2 * CurResLength;
SetArrayLength(Result, CurResLength);
end;
Result[ResLength] := Copy(Source, 1, Position - 1);
ResLength := ResLength + 1;
Delete(Source, 1, Position + DelLength - 1);
until (Position = 0);
SetArrayLength(Result, ResLength - 1);
end;
I derived this based off the previous version. This is faster in only limited cases. Use this if you expect the resulting array to be pretty large; like over 256 elements (actual value may (or may not) vary from machine to machine; I'm not very educated when it comes to that sort of thing). Changing the magic number 2 may cause the 256 magic number to vary. It all depends. On my machine when testing with this setup, having around 256 items seemed to have both versions take the same amount of time.
-
This is truly a lot better than XSplit.. People who use XSplit should paste Explode over their old split function.
-
After even more testing with the help of CurryWurst, we have came up with an even faster version. We cannot think to make this any faster than it already is.
-
When the position is zero, the "repeat" part doesn't get broken. It is repeating the all things below after the position becomes zero.
SetArrayLength(Result, ResLength + 1);
Result[ResLength] := Copy(Source, 1, Position - 1);
ResLength := ResLength + 1;
Delete(Source, 1, Position + DelLength - 1);
Because, it checks whether position is zero, when it finishes repeating the whole "repeat" part.
For example, let's write all lines of a text file which has three lines in it.
... other codes...
for i := 0 to (GetArrayLength(X)-1) do begin
WriteConsole(ID, X[i], RGB(255,215,0));
end;
...other codes...
The output is:
[*] first line
[*] second line
[*] third line
[*] <nothing>
It generates an empty line at the end. So you have to write (GetArrayLength(X)-2) instead of (GetArrayLength(X)-1).
This means that the length of the array is being one more than what it is supposed to be.
So I edited it like this:
function Explode(Source: string; const Delimiter: string): array of string;
var
Position, DelLength, ResLength: integer;
begin
DelLength := Length(Delimiter);
Source := Source + Delimiter;
Position := Pos(Delimiter, Source); <<<<<<<<<<<<<<<<<<<<<<<<
repeat
SetArrayLength(Result, ResLength + 1);
Result[ResLength] := Copy(Source, 1, Position - 1);
ResLength := ResLength + 1;
Delete(Source, 1, Position + DelLength - 1);
Position := Pos(Delimiter, Source); <<<<<<<<<<<<<<<<<<<<<<<<
until (Position = 0);
SetArrayLength(Result, ResLength - 1);
end;
Shouldn't it be like above?
Actually, this edition above might be more slow than the original, I really don't know but probably it is, whatever. Then let's edit just the last line of the function like this:
SetArrayLength(Result, ResLength - 2);
... instead of:
SetArrayLength(Result, ResLength - 1);
Sooo, what do you think? :)
Sorry for my grammar by the way.
-
Never had such problems with this function, maybe you have a delimiter at the end of the exploded text and that's where the empty element comes from
-
Never had such problems with this function, maybe you have a delimiter at the end of the exploded text and that's where the empty element comes from
No I tried both with and without delimiter (at the end), no difference.
-
doesnt readfile add #13#10 in the end of the result string?
-
doesnt readfile add #13#10 in the end of the result string?
I don't know but it probably does because otherwise Explode wouldn't be able to get the last line.
-
Yes dnmr, it does.
-
doesnt readfile add #13#10 in the end of the result string?
I don't know but it probably does because otherwise Explode wouldn't be able to get the last line.
On behalf of your IRC request I reviewed the code and did some tests. To put the results in a nutshell I did not spot any misbehaviour. As tk, dnmr and ExHunter correctly imply and even explain, it only happens if you use the ReadFile() (http://devs.soldat.pl/index.php/ReadFile)function which reflects proper behaviour.
If you still think the function does not work as expected, I would appreciate if you may provide some test scripts to reproduce the issues you encounter.
Thanks for your feedback.
Markus