gmod_game: Better/shorter string.Explode suggested by TomyLob..

Revision 875
Better/shorter string.Explode suggested by TomyLobo Changed Files:

Committed By Alexander Overvoorde

You committed the wrong one, without the modifications I sent you later.
Also, in the meantime, Divran found out that this version sucks for long strings so I wrote another one that performs much better for long strings but worse for short ones and he combined the two into this:

divran did some more benchmarks, he’ll post an optimized version of of that 2nd version in a minute

Just in case Divran’s pastebin disappears, here’s a gist mirror:

Here are some test results.

“Explode1” is one with both of the two explode functions described below, with a string length check (see the code above).
“Explode2” is the one with only the “()” … sep … “()” pattern.
“Explode3” is the one with the “(.-)” … sep … “()” pattern.

Test results:

This means that #3 (the one with the “(.-) … ()” pattern) is faster than #2 (the one with “() … ()”) when the parts in between the separators are very short. The length of the string does not matter.
The time #3 takes to finish depend on the length of the parts. When they get bigger, the function gets slower.
#2 does not suffer from this at all and runs at a constant speed pretty much all the time. It runs slightly slower when there are multiple separators in the string, but that’s barely noticeable.

I’d go with #2.

I just tried localizing string.sub at the top, and that made #2 another 0.01 seconds faster when running the third test.
And by the way, here’s the final code:
[lua]local totable = string.ToTable
local string_sub = string.sub
local string_gsub = string.gsub
local string_gmatch = string.gmatch
function string.Explode(separator, str, withpattern)
if (separator == “”) then return totable( str ) end

local ret = {}
local index,lastPosition = 1,1

-- Escape all magic characters in separator
if not withpattern then separator = string_gsub( separator, "[%-%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1" ) end

-- Find the parts
for startPosition,endPosition in string_gmatch( str, "()" .. separator.."()" ) do
    ret[index] = string_sub( str, lastPosition, startPosition-1)
    index = index + 1
    -- Keep track of the position
    lastPosition = endPosition

-- Add last part by using the position we stored
ret[index] = string_sub( str, lastPosition)
return ret


Alright, but this is the last time I’m going to change it.

Please use this for string.Replace, your one doesn’t stop the pattern patching properly.

local MAGIC_CHARACTERS = “([%(%)%.%%%+%-%*%?%[%^%$])”;

function string.Replace(text, find, replace)
return ( text:gsub(find:gsub(MAGIC_CHARACTERS, “%%%1”), replace) );