Profiling replacing substring ignoring case
;==========================================================================================================================================
; Replace all occurrences of a sub-string with another string, ignoring case.
;
; Profiling Performance Contest.
;
;   - udfStrReplaceNC_1  (Marty Williams.20020516)   (Slightly modified by Detlev Dalitz.20020517.20090523.20110330.)
;   - udfStrReplaceNC_2  (Bill Meek.20020516)        (Slightly modified by Detlev Dalitz.20020517.20090523.)
;   - udfStrReplaceNC_3  (Lars M. Doornbos.20110330) (Slightly modified by Detlev Dalitz.20110330.)
;
;------------------------------------------------------------------------------------------------------------------------------------------
; (c)Detlev Dalitz.20110329.20110330.
;==========================================================================================================================================


; How many different test cases?
intContestCaseMax = 5

; How many loops to run?
intContestLoopMax = 20

; What group of contestants to examine?
intContestantMin = 1
intContestantMax = 3

; Display preview of test case results?
blnDisplayPreview = @TRUE
;blnDisplayPreview = @FALSE

; Display contest status in windows title?
blnDisplayStatus = @TRUE
;blnDisplayStatus = @FALSE

GoSub DEFINE_CONTEST_FUNCTIONS


;==========================================================================================================================================
GoSub DEFINE_FUNCTIONS

; Run the contest once and display the results for verifying.
; Then press CANCEL to abort or OK to run complete contest.
If blnDisplayPreview
   For intContestCase = 1 To intContestCaseMax
      udsPrepareTestCase (intContestCase)
      udsPrepareCounters ()
      For intContestant = intContestantMin To intContestantMax
         udsRunContestant (intContestant)
      Next
      If @CANCEL == udfArrayDumpToItemList (arrContestResults, intContestantMin, intContestantMax, @LF) Then Goto CANCEL
   Next
EndIf

; Run complete contest.
WinShow ("")
strContestResult = ""

Switch blnDisplayStatus
Case @TRUE
   For intContestCase = 1 To intContestCaseMax
      udsPrepareTestCase (intContestCase)
      udsPrepareCounters ()
      For intContestLoop = 1 To intContestLoopMax
         For intContestant = intContestantMin To intContestantMax
            WinTitle ("", "Profiling|Case=" : intContestCaseMax : "." : intContestCase : "|Contestant=" : intContestantMax : "." : intContestant : "|Loop=" : intContestLoopMax : "." : intContestLoop)
            udsRunContestant (intContestant)
         Next
      Next
      strContestResult = strContestResult : @LF : udsResultPerTestCase ()
   Next
   Break
Case @FALSE
   For intContestCase = 1 To intContestCaseMax
      udsPrepareTestCase (intContestCase)
      udsPrepareCounters ()
      For intContestLoop = 1 To intContestLoopMax
         For intContestant = intContestantMin To intContestantMax
            udsRunContestant (intContestant)
         Next
      Next
      strContestResult = strContestResult : @LF : udsResultPerTestCase ()
   Next
   Break
EndSwitch

strContestResult = strContestResult : @LF : strPre : StrFill ("-", intLenSum)
strContestResult = StrSub (strContestResult, 2, -1)

Message (strMsgTitle, strContestResult)
ClipPut (StrReplace (strContestResult, @LF, @CRLF))

:CANCEL
Exit
;==========================================================================================================================================



;==========================================================================================================================================
:DEFINE_CONTEST_FUNCTIONS
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsPrepareTestCase (intContestCase)
Switch intContestCase
Case 1
   strBase = '"Hello Cat" the dog said to the cAt.' ; String of 36 characters, 2 replacements.
   strOld = "cat"
   strNew = "SammySammySammySammySammy"
   intCount = StrCnt (strBase, strOld, 1, -1, 0)
   Break
Case 2
   strBase = StrFill ("Hello there, and again hello again.", 1050)  ; String of 1050 characters, 60 replacements.
   strOld = "HELLO"
   strNew = "Bye"
   intCount = StrCnt (strBase, strOld, 1, -1, 0)
   Break
Case 3
   strBase = FileGet (IntControl (1004, 0, 0, 0, 0)) ; Use this script as test input, 27 replacements.
   strOld = "new"
   strNew = "new"
   intCount = StrCnt (strBase, strOld, 1, -1, 0)
   Break
Case 4
   strBase = FileGet (IntControl (1004, 0, 0, 0, 0)) ; Use this script as test input, about 260 replacements.
   strOld = "str"
   strNew = "STRING_"
   intCount = StrCnt (strBase, strOld, 1, -1, 0)
   Break
Case 5
   strBase = FileGet (IntControl (1004, 0, 0, 0, 0)) ; Use this script as test input, about 2600 replacements.
   strOld = "-"
   strNew = "-.-."
   intCount = StrCnt (strBase, strOld, 1, -1, 0)
   Break
EndSwitch
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsRunContestant (intContestant)
Exclusive (@ON)
Switch intContestant
Case 1
   arrContestants[intContestant] = "udfStrReplaceNC_1"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfStrReplaceNC_1 (strBase, strOld, strNew)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

Case 2
   arrContestants[intContestant] = "udfStrReplaceNC_2"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfStrReplaceNC_2 (strBase, strOld, strNew)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

Case 3
   arrContestants[intContestant] = "udfStrReplaceNC_3"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfStrReplaceNC_3 (strBase, strOld, strNew)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

EndSwitch
Exclusive (@OFF)
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfStrReplaceNC_1 (strBase, strOld, strNew)
intLenBase = StrLen (strBase)
intLenOld = StrLen (strOld)
intLenNew = StrLen (strNew)
intBBSize = intLenBase
If intLenNew > intLenOld Then intBBSize = intBBSize + StrCnt (strBase, strOld, 1, -1, 0) * (intLenNew - intLenOld)
hdlBB = BinaryAlloc (intBBSize)
BinaryPokeStr (hdlBB, 0, strBase)
BinaryReplace (hdlBB, strOld, strNew, @FALSE)
strOut = BinaryPeekStr (hdlBB, 0, BinaryEodGet (hdlBB))
hdlBB = BinaryFree (hdlBB)
Return strOut
;..........................................................................................................................................
; Adapted from
; Conf:  WinBatch
; From:  Marty marty+bbs@winbatch.com
; Date:  Thursday, May 16, 2002 01:01 PM
;..........................................................................................................................................
; Slighty modified by Detlev Dalitz.20020517.20090523.20110330.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfStrReplaceNC_2 (strBase, strOld, strNew)
intLenNew = StrLen (strNew)
intLenOld = StrLen (strOld)
intPos = 0
While @TRUE
   intPos = StrIndexNC (strBase, strOld, intPos, @FWDSCAN)
   If !intPos Then Break
   strBase = StrSub (strBase, 1, intPos - 1) : strNew : StrSub (strBase, intPos + intLenOld, -1)
   intPos = intPos + intLenNew
EndWhile
Return strBase
;..........................................................................................................................................
; Adapted from
; Conf:  WinBatch
; From:  billmeek winbatch@tfic.com
; Date:  Thursday, May 16, 2002 01:24 PM
;..........................................................................................................................................
; Slighty modified by Detlev Dalitz.20020517.20090523.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfStrReplaceNC_3 (strBase, strOld, strNew)
intLenNew = StrLen (strNew)
intLenOld = StrLen (strOld)
intPos = -intLenNew
While @TRUE
   intPos = StrIndexNC (strBase, strOld, intPos + intLenNew, @FWDSCAN)
   If !intPos Then Break
   strBase = StrSub (strBase, 1, intPos - 1) : strNew : StrSub (strBase, intPos + intLenOld, -1)
EndWhile
Return strBase
;..........................................................................................................................................
; Adapted from
; Conf:  WinBatch Script Exchange
; From:  lars doornbos l.m.doornbos@planet.nl
; Date:  Tuesday, March 29, 2011 11:35 PM
;..........................................................................................................................................
; Slighty modified by Detlev Dalitz.20110330.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;==========================================================================================================================================
Return ; from GoSub DEFINE_CONTEST_FUNCTIONS
;==========================================================================================================================================



;==========================================================================================================================================
:DEFINE_FUNCTIONS
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayDumpToItemList (arrArray, intFirst, intLast, strDelimiter)
If !ArrInfo (arrArray, -1) Then Return "*ARRAY_IS_INVALID*" ; No Array, return invalid itemlist, i. e. empty string "".
If ArrInfo (arrArray, 0) != 1 Then Return "*ARRAY_IS_NOT_DIM_1*" ; Array is not a dim-1 array, return invalid itemlist, i. e. empty string "".
intElements = ArrInfo (arrArray, 1)
If intElements == 0 Then Return "*ARRAY_HAS_NO_ELEMENTS*" ; Array has no element.
intFirst = Min (Max (intFirst, 0), intElements - 1)
intLast = Min (Max (intLast, 0), intElements - 1)
strItemList = ""
intFixSize = StrLen (intLast)
For intI = intFirst To intLast
   If !!VarType (arrArray [intI])
      If arrArray [intI] == ""
         strItemList = ItemInsert (StrFixLeft (intI, "0", intFixSize) : "|" : "*ARRAY_ELEMENT_IS_EMPTY_STRING*", -1, strItemList, strDelimiter)
      Else
         arrArray [intI] = StrReplace (StrReplace (StrReplace (StrReplace (arrArray [intI], @CRLF, "@CRLF"), @CR, "@CR"), @LF, "@LF"), @TAB, "@TAB") ; Make WB style.
         arrArray [intI] = StrSub (arrArray [intI], 1, 200) ; Special truncation just for the small buffer of AskItemList.
         strItemList = ItemInsert (StrFixLeft (intI, "0", intFixSize) : "|" : arrArray [intI], -1, strItemList, strDelimiter)
      EndIf
   Else
      strItemList = ItemInsert (StrFixLeft (intI, "0", intFixSize) : "|" : "*ARRAY_ELEMENT_IS_UNDEFINED*", -1, strItemList, strDelimiter)
   EndIf
Next
IntControl (28, 1, 0, 0, 0)
IntControl (63, 050, 200, 950, 800)
Return AskItemlist ("Profiling|Preview Contestant Result (max. 255 characters per item line)", strItemList, strDelimiter, @UNSORTED, @SINGLE) ; This returns a Unicode string of VarType=128.
:CANCEL
Return @CANCEL
;..........................................................................................................................................
; This UDF "udfArrayDumpToItemList" reads a dim-1 array and returns an itemlist of all array cell items within an AskItemList dialog..
;
; Return values:
; "*ARRAY_IS_INVALID*"              ... Invalid array resp. this is no array.
; "*ARRAY_IS_NOT_DIM_1*"            ... Array is not a dim-1 array.
; "*ARRAY_HAS_NO_ELEMENTS*"         ... Array has no element.
; "*ARRAY_ELEMENT_IS_EMPTY_STRING*" ... Array element has vartype STRING but is empty.
; "*ARRAY_ELEMENT_IS UNDEFINED*"    ... Array element has undefined VarType.
; value                             ... Current value of the array element.
;
; Example: strItemList = udfArrayDumpToItemList (arrArray, 0, 19, @TAB)
;
; Detlev Dalitz.20090515.20100122.20101222.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsPrepareCounters ()
arrContestants = ArrDimension (1 + intContestantMax)    ; Array index 0 not used.
arrContestResults = ArrDimension (1 + intContestantMax) ; Array index 0 not used.
arrContestTicks = ArrDimension (1 + intContestantMax)   ; Array index 0 used for the sum.
arrContestPct = ArrDimension (1 + intContestantMax)     ; Array index 0 not used.
ArrInitialize (arrContestants, "")
ArrInitialize (arrContestResults, "")
ArrInitialize (arrContestTicks, 0)
ArrInitialize (arrContestPct, 0.0)
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsResultPerTestCase ()
Decimals (1)
For intContestant = intContestantMin To intContestantMax
   arrContestTicks[0] = arrContestTicks[0] + arrContestTicks[intContestant]
Next
intContestTicksMin = arrContestTicks[0]
For intContestant = intContestantMin To intContestantMax
   intContestTicksMin = Min (intContestTicksMin, arrContestTicks[intContestant])
Next
If arrContestTicks[0] < 1 Then arrContestTicks[0] = 1 ; To prevent dividing by zero.
For intContestant = intContestantMin To intContestantMax
   arrContestPct[intContestant] = 100.0 * arrContestTicks[intContestant] / arrContestTicks[0]
Next

; Format output.
strMsgTitle = "Performance Contest Result"
strTest = "Test"
strTicks = "Ticks"
strPct = "Pct"
strContestant = "Contestant"
strCase = "Contest Case = "
strIter = "Iterations = "
strSep = "  "
strPre = "; "
strWinner = "<== The Winner"
strDT = "DateTime = "
intLenTest = Max (StrLen (strTest), StrLen (intContestantMax))
intLenTicks = StrLen (strTicks)
intLenPct = StrLen (strPct)
intLenContestant = StrLen (strContestant)
intLenSep = StrLen (strSep)
intLenWinner = StrLen (strWinner)
For intContestant = intContestantMin To intContestantMax
   intLenTicks = Max (intLenTicks, StrLen (arrContestTicks[intContestant]))
   intLenPct = Max (intLenPct, StrLen (arrContestPct[intContestant]))
   intLenContestant = Max (intLenContestant, StrLen (arrContestants[intContestant]))
Next
intLenSum = intLenTest + intLenTicks + intLenPct + intLenContestant + intLenWinner + 4 * intLenSep
strTest = StrFixLeft (strTest, " ", intLenTest)
strTicks = StrFixLeft (strTicks, " ", intLenTicks)
strPct = StrFixLeft (strPct, " ", intLenPct)
strResult = strPre : StrFill ("-", intLenSum) : @LF : strPre : strMsgTitle
strResult = strResult : @LF : strPre : strCase : intContestCase
strResult = strResult : @LF : strPre : strIter : intContestLoopMax
strResult = strResult : @LF : strPre : strTest : strSep : strTicks : strSep : strPct : strSep : strContestant
For intContestant = intContestantMin To intContestantMax
   strTest = StrFixLeft (intContestant, " ", intLenTest)
   strTicks = StrFixLeft (arrContestTicks[intContestant], " ", intLenTicks)
   strPct = StrFixLeft (arrContestPct[intContestant], " ", intLenPct)
   strContestant = StrFix (arrContestants[intContestant], " ", intLenContestant)
   If arrContestTicks[intContestant] == intContestTicksMin Then strContestant = strContestant : strSep : strWinner
   strResult = strResult : @LF : strPre : strTest : strSep : strTicks : strSep : strPct : strSep : strContestant
Next
Return strResult : @LF : strPre : strDT : TimeYmdHms ()
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------

;==========================================================================================================================================
Return ; from GoSub DEFINE_FUNCTIONS
;==========================================================================================================================================

; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 1
; Iterations = 200
; Test  Ticks   Pct  Contestant
;    1    376  26.7  udfStrReplaceNC_1  <== The Winner
;    2    563  40.0  udfStrReplaceNC_2
;    3    468  33.3  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:33:58
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 2
; Iterations = 200
; Test  Ticks   Pct  Contestant
;    1    205   1.1  udfStrReplaceNC_1  <== The Winner
;    2   9254  51.0  udfStrReplaceNC_2
;    3   8702  47.9  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:34:18
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 3
; Iterations = 200
; Test  Ticks   Pct  Contestant
;    1   1579   5.4  udfStrReplaceNC_1  <== The Winner
;    2  14003  48.3  udfStrReplaceNC_2
;    3  13430  46.3  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:34:48
; ----------------------------------------------------


; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 1
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1     32  20.5  udfStrReplaceNC_1  <== The Winner
;    2     62  39.7  udfStrReplaceNC_2
;    3     62  39.7  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:36:12
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 2
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1     62   3.5  udfStrReplaceNC_1  <== The Winner
;    2    892  49.6  udfStrReplaceNC_2
;    3    843  46.9  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:36:14
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 3
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1    203   6.8  udfStrReplaceNC_1  <== The Winner
;    2   1407  47.4  udfStrReplaceNC_2
;    3   1359  45.8  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:36:17
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 4
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1    248   0.9  udfStrReplaceNC_1  <== The Winner
;    2  13563  50.2  udfStrReplaceNC_2
;    3  13203  48.9  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:36:44
; -----------------------------------------------------
; Performance Contest Result
; Contest Case = 5
; Iterations = 20
; Test   Ticks   Pct  Contestant
;    1     232   0.1  udfStrReplaceNC_1  <== The Winner
;    2  145831  50.3  udfStrReplaceNC_2
;    3  143812  49.6  udfStrReplaceNC_3
; DateTime = 2011:03:30:11:41:34
; -----------------------------------------------------