Profiling extracting substring from string
;==========================================================================================================================================
; Extract substring from string.
;
; Profiling Performance Contest.
;
;   - udfStringExtract_1
;   - udfStringExtract_2
;   - udfStringExtract_3
;
;------------------------------------------------------------------------------------------------------------------------------------------
;
;   Topic:  Several StrIndex's
;   Conf:  WinBatch
;   From:  MW4
;   Date:  Wednesday, January 05, 2011 12:03 PM
;
;   No -- there is text after that I need, but I need that "X" line position to grab that.
;
;   Better example:
;
;   as de 123dek / ab16 fb Xjdheeh BVP 34319 21489
;   kfj jo200 / hb47 fb32 Xjwjw BVP 51123 81000
;   ke kl5 / jh23 fb1 Xokeksmdd BVP 21000 21000
;   5 5 5 e krk / uy56 fb44 Xssd BVP 21000 21000
;
;   The right part (right of my X) starting with BVP is fixed at BVP, space, 5 digits, space, 5 digits
;
;   The left part (left of the X) is completely variable in size and number of spaces to the left of
;   the "/", but the "/" and the three spaces to the right are always there.
;
;   The "X" part that I need to pull is always variable in size.
;
;------------------------------------------------------------------------------------------------------------------------------------------
; (c)Detlev Dalitz.20110105.
;==========================================================================================================================================


; How many different test cases?
intContestCaseMax = 4

; How many loops to run?
intContestLoopMax = 1000

; 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
   strLine = "as de 123dek / ab16 fb Xjdheeh BVP 34319 21489"
   Break
Case 2
   strLine = "kfj jo200 / hb47 fb32 Xjwjw BVP 51123 81000"
   Break
Case 3
   strLine = "ke kl5 / jh23 fb1 Xokeksmdd BVP 21000 21000"
   Break
Case 4
   strLine = "5 5 5 e krk / uy56 fb44 Xssd BVP 21000 21000"
   Break
EndSwitch
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsRunContestant (intContestant)
Exclusive (@ON)
Switch intContestant
Case 1
   arrContestants[intContestant] = "udfStringExtract_1"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfStringExtract_1 (strLine)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

Case 2
   arrContestants[intContestant] = "udfStringExtract_2"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfStringExtract_2 (strLine)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

Case 3
   arrContestants[intContestant] = "udfStringExtract_3"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfStringExtract_3 (strLine)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

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


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfStringExtract_1 (strLine)
intItemPos = StrIndex (strLine, " BVP ", 1, @FWDSCAN)
intSpacePos = StrIndex (strLine, " ", intItemPos - 1, @BACKSCAN)
Return StrSub (strLine, intSpacePos + 1, intItemPos - intSpacePos)
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfStringExtract_2 (strLine)
Return ItemExtract (-1, ItemRemove (-1, StrReplace (strLine, " BVP ", @TAB), @TAB), " ")
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfStringExtract_3 (strLine)
Return ItemExtract (-1, StrSub (strLine, 1, StrLen (strLine) - 16), " ")
#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", 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 = 10000
; Test  Ticks   Pct  Contestant
;    1   7473  44.5  udfStringExtract_1
;    2   4783  28.5  udfStringExtract_2
;    3   4523  27.0  udfStringExtract_3  <== The Winner
; DateTime = 2011:01:06:09:06:14
; -----------------------------------------------------
; Performance Contest Result
; Contest Case = 2
; Iterations = 10000
; Test  Ticks   Pct  Contestant
;    1  10346  42.9  udfStringExtract_1
;    2   7143  29.6  udfStringExtract_2
;    3   6629  27.5  udfStringExtract_3  <== The Winner
; DateTime = 2011:01:06:09:07:24
; -----------------------------------------------------
; Performance Contest Result
; Contest Case = 3
; Iterations = 10000
; Test  Ticks   Pct  Contestant
;    1  16167  44.8  udfStringExtract_1
;    2  10445  29.0  udfStringExtract_2
;    3   9452  26.2  udfStringExtract_3  <== The Winner
; DateTime = 2011:01:06:09:09:11
; -----------------------------------------------------
; Performance Contest Result
; Contest Case = 4
; Iterations = 10000
; Test  Ticks   Pct  Contestant
;    1  17907  42.1  udfStringExtract_1
;    2  12819  30.1  udfStringExtract_2
;    3  11805  27.8  udfStringExtract_3  <== The Winner
; DateTime = 2011:01:06:09:11:17
; -----------------------------------------------------