Edit: Fixed typo in MP_StripPrefixRecEx.
As I noted in another thread, recursive functions typically represent convenience for the programmer, but more work for the computer.
Optimizing recursive functions is a big topic Tim, and not one I'm particularly qualified to author, but I would say that when writing recursive functions some of the things you have to do are eliminate redundant function calls and variable declarations.
For example -- pretending that vl-string-position doesn't have the optional "start from the end" argument let's write a recursive variant that employs a common technique: write core (recursive) functionality as a function that is initially invoked via a wrapper --
(defun MP_StripPrefixRecEx ( string code )
;; Not to be called directly, only via wrapper
;; function MP_StripPrefixRec.
;;
;; Uses argument 'code' which is calculated
;; using the ascii function only once, by the
;; calling / parent code.
;;
;; Uses global scope variable 'position' declared
;; by the calling code (or fully global if the
;; parent code does not declare said variable),
;; so it doen't have to push more onto the stack
;; with each successive iteration than is absolutely
;; esssential.
(if (setq position (vl-string-position code string))
(MP_StripPrefixRecEx
(substr string (+ 2 position))
code
)
String
)
)
(defun MP_StripPrefixRec ( string delim / position )
;; I am the wrapper code, responsible for doing any
;; preprocessing, e.g. the (ascii delim) call as well
;; as declaring any variables that are used in the
;; MP_StripPrefixRecEx function, like the 'position'
;; variable.
;;
;; Generally speaking this is bad, bad coding practice as
;; it requires one function to have intimate knowledge
;; of the inner workings of another function, breaking
;; black box rules and making for all kinds of potential
;; maintenance woes. In this case I'm saying "it's ok"
;; because this function is written entirely in the
;; context of the other -- the two work together.
(MP_StripPrefixRecEx string (ascii delim))
)
Having spent the time to optimize a little bit, the actual benefits may not be realized until the recurse levels get a little deep, as the following illuminates --
Using testString = "123" ...
Elapsed milliseconds / relative speed for 32768 iteration(s):
(TW_STRIPSTRING TESTSTRING "|")........1281 / 1.04 <fastest>
(MP_STRIPPREFIXREC TESTSTRING "|").....1328 / 1.00 <slowest>
Using testString = "123|456" ...
Elapsed milliseconds / relative speed for 32768 iteration(s):
(MP_STRIPPREFIXREC TESTSTRING "|").....1469 / 1.02 <fastest>
(TW_STRIPSTRING TESTSTRING "|")........1500 / 1.00 <slowest>
Using testString = "123|456|789" ...
Elapsed milliseconds / relative speed for 32768 iteration(s):
(MP_STRIPPREFIXREC TESTSTRING "|").....1562 / 1.02 <fastest>
(TW_STRIPSTRING TESTSTRING "|")........1593 / 1.00 <slowest>
Using testString = "123|456|789|ABC" ...
Elapsed milliseconds / relative speed for 32768 iteration(s):
(MP_STRIPPREFIXREC TESTSTRING "|").....1562 / 1.06 <fastest>
(TW_STRIPSTRING TESTSTRING "|")........1656 / 1.00 <slowest>
Using testString = "123|456|789|ABC|DEF" ...
Elapsed milliseconds / relative speed for 32768 iteration(s):
(MP_STRIPPREFIXREC TESTSTRING "|").....1593 / 1.12 <fastest>
(TW_STRIPSTRING TESTSTRING "|")........1781 / 1.00 <slowest>
Using testString = "123|456|789|ABC|DEF|GHI|JKL|MNO|PQR" ...
Elapsed milliseconds / relative speed for 32768 iteration(s):
(MP_STRIPPREFIXREC TESTSTRING "|").....1781 / 1.18 <fastest>
(TW_STRIPSTRING TESTSTRING "|")........2093 / 1.00 <slowest>
Sorry, that's all I've got for now.