Jump to content

Recommended Posts

Posted (edited)

After the above discussion, I decided to combine my approach with some of AZIJO's ideas. This is an improvement on my previous code.

A very nearly universal delimiter testing function:

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w- 7

#include <Array.au3>
#include <String.au3>

Example()

Func Example()
    Local $sStr = "" ; Monster string for testing
    For $i = 1 To 10000000
        $sStr &= Chr(Random(1, 255, 1))
    Next

    MsgBox(0, "First 300 out of 10000000 Chracters", StringLeft($sStr, 300))
    Local $sDelim = _GetDelim($sStr)
    If Not @error Then
        ConsoleWrite("<---| " & $sDelim & " |--->" & @LF)
    Else
        ConsoleWrite("<---| FAILED |--->" & @LF)
    EndIf
EndFunc

Func _GetDelim($sTest)
    If Not IsString($sTest) Then Return SetError(1, 0, "") ; Invalid Input String.

    Local $aAscII[31], $sDelim ; Using Control Characters only.
    ; First try one character
    For $i = 1 To 31
        $sDelim = Chr($i)
        If Not StringInStr($sTest, $sDelim, 1) Then
            Return $sDelim
        Else
            $aAscII[$i - 1] = $sDelim ; Needed for the next stage.
        EndIf
    Next

    ; That failed - so we try two characters.
    Local $aDoubleChar = _ArrayCombinations($aAscII, 2, "")
    For $i = 1 To $aDoubleChar[0]
        $sDelim = $aDoubleChar[$i]
        If Not StringInStr($sTest, $sDelim, 1) Then Return $sDelim
    Next

    ; That failed - so we try the reverse patterns.
    ReDim $aDoubleChar[931]
    $aDoubleChar[0] = 930

    For $i = 466 To $aDoubleChar[0]
        $sDelim = _StringReverse($aDoubleChar[$i -465])
        If Not StringInStr($sTest, $sDelim, 1) Then
            Return $sDelim
        Else
            $aDoubleChar[$i] = $sDelim ; Needed for the next stage.
        EndIf
    Next

    ; That failed - so we try three characters.
    For $i = 1 To $aDoubleChar[0]
        For $j = 0 To 30
            $sDelim = $aDoubleChar[$i] & $aAscII[$j]
            If Not StringInStr($sTest, $sDelim, 1) Then Return $sDelim
        Next
    Next

    ; That failed - so we try four characters.
    For $i = 1 To $aDoubleChar[0]
        For $j = 1 To $aDoubleChar[0]
            $sDelim = $aDoubleChar[$i] & $aDoubleChar[$j]
            If Not StringInStr($sTest, $sDelim, 1) Then Return $sDelim
        Next
    Next

    ; That failed - so we try five characters.
    For $i = 1 To $aDoubleChar[0]
        For $j = 1 To $aDoubleChar[0]
            For $k = 0 To 30
                $sDelim = $aDoubleChar[$i] & $aDoubleChar[$j] & $aAscII[$k]
                If Not StringInStr($sTest, $sDelim, 1) Then Return $sDelim
            Next
        Next
    Next

    ; Here we could also try six characters followed by seven etc.
    Return SetError (2, 0, "") ; No suitable delimiter found.
EndFunc
Edited by czardas
Posted

Thanks for the sample code czardas :thumbsup:

I ran these tests:

Global $sStr = ''
For $i = 1 To 10000000
    $sStr &= Chr(Random(1, 255, 1)) ; Monster string for testing.
Next
MsgBox(0, 'Info', 'Test String Created')

Global $sDelim = _GetDelim($sStr)
MsgBox(0, 'Delim', Binary($sDelim)) ; Show control characters.
MsgBox(0, 'StringInStr?', StringInStr($sStr, $sDelim))

Func _GetDelim($sTest)
    Local $sDelim = Chr(1)
    While StringInStr($sTest, $sDelim)
        $sDelim &= Chr(Random(1, 31, 1))
        If 32 = StringLen($sDelim) Then Return SetError(3, 0, 0)
    WEnd
    Return $sDelim
EndFunc

Response time is relatively slow due to the monster test string. _GetDelim itself takes 1-3 iterations to find a unique delimiter. I'm happy with that, the delimiter is 2-3 characters on average.

A lookup on a 10 million character string takes some time, I didn't measure exactly but roughly 1-2 seconds before the delimiter pops up.

I reduced that by checking only the first 100000 characters of the string, but that's too small a sample, I got collisions outside the test range.

Same for a 1 million test sample, it performs better but only marginally, you get collisions now and then.

I took out the Random and took your sequential approach:

Func _GetDelim($sTest)
    Local $sDelim
    ;$sTest = StringLeft($sTest, 1000000) ; Reduced test sample.
    For $i = 1 To 31
        $sDelim &= Chr($i)
        If Not StringInStr($sTest, $sDelim) Then ExitLoop
        If 32 = StringLen($sDelim) Then Return SetError(3, 0, 0)
    Next
    Return $sDelim
EndFunc

I haven't kept exact stats but on gut feeling I'd say it performs only marginally better because there's one less function call. When testing a smaller sample range (1 million) it gives less collisions, but it still isn't foolproof.

So as far as methods go, I'd say the sequential approach is marginally faster but not much.

I simplified the function because I feel matters shouldn't be made overly complicated. Any unique sequence of characters will do, it's just a throw-away value anyway so the simplest approach will suffice.

I don't see a way to reduce overall speed for very large monster strings though.

So this would be my proposed version, corrections and all:

; #FUNCTION# ===================================================================
; Name...........: _StringRegExpSplit
; Description ...: Split a string according to a regular exp[b][/b]ression.
; Syntax.........: _StringRegExpSplit($sString, $sPattern)
; Parameters ....: $sString - String: String to split.
;                  $sPattern - String: Regular exp[b][/b]ression to split on.
; Return values .: Success - Array: Array of substrings, the total is in $array[0].
;                  Failure - Array: The count is 1 ($array[0]) and the full string is returned ($array[1]) and sets @error:
;                  |1 Delimiter not found.
;                  |2 Bad RegExp pattern, @extended contains the offset of the error in the pattern.
;                  |3 No suitable placeholder delimiter could be constructed.
; Author ........: dany
; Modified ......: czardas, AZJIO
; Remarks .......:
; Related .......:
; ==============================================================================
Func _StringRegExpSplit($sString, $sPattern)
    Local $sSplit, $sDelim, $aError[2] = [1, $sString]
    For $i = 1 To 31
        $sDelim &= Chr($i)
        If Not StringInStr($sString, $sDelim) Then ExitLoop
        If 32 = StringLen($sDelim) Then Return SetError(3, 0, $aError)
    WEnd
    $sSplit = StringRegExpReplace($sString, $sPattern, $sDelim)
    If @error Then Return SetError(2, @extended, $aError)
    If @extended = 0 Then Return SetError(1, 0, $aError)
    If Not IsBinary($sString) Then Return StringSplit($sSplit, $sDelim, 1)
    $sSplit = StringSplit($sSplit, $sDelim, 1)
    For $i = 2 To $sSplit[0]
        $sSplit[$i] = '0x' & $sSplit[$i]
    Next
    Return $sSplit
EndFunc

[center]Spiderskank Spiderskank[/center]GetOpt Parse command line options UDF | AU3Text Program internationalization UDF | Identicon visual hash UDF

  • 4 weeks later...
Posted

...
For $i = 1 To 31
$sDelim &= Chr($i)
If Not StringInStr($sString, $sDelim) Then ExitLoop
If 32 = StringLen($sDelim) Then Return SetError(3, 0, $aError)
WEnd
...

@dany

You made a small typo converting the _StringRegExpSplit delimiter-finder from random to sequential: That should be a For...Next loop, not a For...WEnd loop. :bye:

I discovered the glitch because I used your snippet while writing my own improving on StringRegExp. When I'm finished (shortly) it will return the position of a match instead of just True or False (in other words, it will make StringRegExp behave more-or-less like StringInStr).

Posted (edited)

Here, as promised, is my snippet that makes StringRegExp (mode 0) behave like StringInStr, in the sense that the return value is the position of the regular expression pattern within the test string, rather than just 1 (match) or 0 (no match). @Extended returns the number of matches within the test string.

Like StringInStr, you can optionally pass which occurrence or which character to start at within the test string. I didn't include a 'case' option since that's built in to regular expressions, and I didn't include a count option because I couldn't figure out what the default would be (infinity? eleventy-billion?).

UPDATE: 'If StringLen($sDelim) = 32 Then...' repositioned and rewritten per suggestions below from AZJIO and guinness.

; #FUNCTION# =====================================================================
; Name ..........: _StringRegExpPos
; Description ...: Returns the position of a regular expression pattern within
;                    a string, similar to StringInStr
; AutoIt Version : V3.3.8.1
; Syntax ........: _StringRegExpPos($sTest, $sPattern, $iOcc, $iStart)
; Parameter(s): .: $sTest      - The string to evaluate
;                 $sPattern    - The regular expression to compare. See
;                                    StringRegExp for pattern definition characters.
;                   $iOcc        - Optional: Which occurrence of the regex to find
;                                    within the test string (Default = 1)
;                   $iStart        - Optional: The starting position of the search
;                                    (Default = 1)
; Return Value ..: Success    - Returns the position of the regex pattern
;                 Failure     - Returns 0 if regex pattern not found
;                 @ERROR       - 0: Normal operation @Extended = number of matches
;                                  1: Invalid "start" or "occurrence" parameter
;                                  2: Pattern invalid. @Extended = offset of error.
; Author(s) .....: Tim Curran (tim at timcurran dot com)
; Date ..........: 9 January 2013
; Link ..........:
; Related .......: StringInStr, StringRegExpReplace, _StringRegExpSplit
; Example .......: Yes
; ================================================================================
Func _StringRegExpPos($sTest, $sPattern, $iOcc = 1, $iStart = 1)
    Local $sDelim, $iHits
    If $iStart > StringLen($sTest) Then Return SetError(1)
    ;Delimiter creation snippet by dany from his version of _StringRegExpSplit
    For $i = 1 To 31
        $sDelim &= Chr($i)
        If Not StringInStr($sTest, $sDelim) Then ExitLoop
    Next
    If StringLen($sDelim) = 32 Then Return SetError(3, 0, 0)
    Local $aResults = StringRegExpReplace(StringMid($sTest, $iStart + (StringLen($sDelim) * ($iOcc - 1))), "(" & $sPattern & ")", $sDelim & "$1")
    If @error = 2 Then Return SetError(2, @extended, 0)
    $iHits = @extended
    If $iHits = 0 Then Return 0
    If $iOcc > $iHits Then Return SetError(1)
    Local $iPos = StringInStr($aResults, $sDelim, 0, $iOcc)
    SetExtended($iHits)
    Return $iStart - 1 + $iPos
EndFunc ;<== _StringRegExpPos

And here's some demo code:

;                111111111122            2222222233333333334444
;    123456789012345678901           2345678901234567890123
$demo = "Will this blast last " & Chr(1) & "or is it fading fast?"
$pos = _StringRegExpPos($demo, ".{2}ast", 3, 1)
ConsoleWrite("@error: " & @error & @TAB & "@extended: " & @extended & @CRLF)
;output="@error: 0 @extended: 3"
ConsoleWrite("$pos: " & $pos & @CRLF)
;output="$pos: 38"
Edited by tcurran
Posted

I kind of agree about the looks, but you're technically wrong. The documentation says the == operator should only be used on string comparisons (which this isn't) that are case sensitive (ditto).

It was an error on my part. Fixed the example above.

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Posted (edited)

When making multiple string replacements within a single string, longer strings should generally be replaced first to avoid erroneously replacing substrings within subsequent search patterns. For this we need to sort the search patterns by length (in descending order).

The syntax and error codes are more or less identical to _ArraySort() except only the first four parameters are used. The modified array is returned ByRef. This function will not work with multidimensional arrays.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w- 7

;Sort an array's elements by strting length
;Author czardas

#include-once
#include <Array.au3>

Func _ArraySortByLen(ByRef $aArray, $iDescending =0, $iStart =0, $iEnd =0)
    If Not IsArray($aArray) Or UBound($aArray, 0) > 1 Then Return SetError(1, 0, 0) ; Not a 1D array
    If Not IsInt($iStart) Or Not IsInt($iEnd) Then Return SetError(5, 0, 0) ; Parameters need to be integers.

    Local $iBound = UBound($aArray)
    Local $aElementLen[$iBound][2]
    $iBound -=1

    For $i = 0 To $iBound
        $aElementLen[$i][0] = StringLen($aArray[$i]) ; Get the length of the element
        $aElementLen[$i][1] = $aArray[$i] ; The element to sort
    Next

    _ArraySort($aElementLen, $iDescending, $iStart, $iEnd)
    If @error Then Return SetError(@error, 0, 0) ; See _ArraySort() for error codes 2 to 4.

    For $i = 0 To $iBound
        $aArray[$i] = $aElementLen[$i][1]
    Next
    Return 1
EndFunc ;==> _ArraySortByLen()

I though this might be quite useful, so I posted it here.

Edited by czardas
Posted (edited)

It is purely to create the box with the username etc and the jump title for the wiki

since the geshi was updated they are probably in need of tweaking but i havent checked since i first made them, you only run the code lower down

=== _IsInternetConnected === ; produces the jump title

{{Snippet Header=== ; produces the box
| AuthorURL=35302-guinness=== ; produces the link for user in forums
| AuthorName=guinness
}}


ConsoleWrite("Internet Is Connected" & " = " & _IsInternetConnected() & @CRLF) ; ( Returns "True" Or "False" )

Func _IsInternetConnected()
Local $aReturn = DllCall('connect.dll', 'long', 'IsInternetConnected')
If @error Then
Return SetError(1, 0, False)
EndIf
Return $aReturn[0] = 0
EndFunc ;==>_IsInternetConnected
Edited by Chimaera
  • 5 weeks later...
Posted (edited)

This is a "cleaned version" of mouse enter/move/leave window messages based on those posts :

#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>

Global $_iCount = 0 ;not important, just for the example

#region GUI
Global $hGUI = GUICreate("MyGUI")

#region MouseTracking
Global $_blIsTracking = False

Global Const $TME_LEAVE = 0x2
Global Const $HOVER_DEFAULT = 0xFFFFFFFF

Global Const $tagTRACKMOUSEEVENT = "struct; dword Size; dword Flags; hwnd WndTrack; dword HoverTime; endstruct"

Global $tTrackMouseEvent = DllStructCreate($tagTRACKMOUSEEVENT)
DllStructSetData($tTrackMouseEvent, "Size", DllStructGetSize($tTrackMouseEvent))
DllStructSetData($tTrackMouseEvent, "Flags", $TME_LEAVE)
DllStructSetData($tTrackMouseEvent, "WndTrack", $hGUI)
DllStructSetData($tTrackMouseEvent, "HoverTime", $HOVER_DEFAULT)

Global $pTrackMouseEvent = DllStructGetPtr($tTrackMouseEvent)
#endregion MouseTracking

GUIRegisterMsg($WM_MOUSEMOVE, "WM_MOUSEMOVE")
GUIRegisterMsg($WM_MOUSELEAVE, "WM_MOUSELEAVE")

GUISetState(@SW_SHOW, $hGUI)
#endregion GUI

While GUIGetMsg() <> $GUI_EVENT_CLOSE
    Sleep(10)
WEnd

GUIDelete($hGUI)

Func WM_MOUSELEAVE($hWnd, $Msg, $wParam, $lParam)
    $_blIsTracking = False

    ConsoleWrite("->MOUSE_LEAVE" & @CRLF)

    Return $GUI_RUNDEFMSG
EndFunc ;==>WM_MOUSELEAVE

Func WM_MOUSEMOVE($hWnd, $Msg, $wParam, $lParam)
    If Not $_blIsTracking Then
        $_blIsTracking = True

        DllCall("User32.dll", "int", "TrackMouseEvent", "ptr", $pTrackMouseEvent)

        ConsoleWrite("+>MOUSE_ENTER " & $_iCount & @CRLF)
        $_iCount += 1
    EndIf

    Return $GUI_RUNDEFMSG
EndFunc ;==>WM_MOUSEMOVE
Edited by FireFox
  • 2 weeks later...
Posted (edited)

Some of you started to talk about the Static keyword, so I made an advanced hotkey example using it with the native HotKeySet function.

Edit: Fixed HotKey not released when the GUI is minimized.

Edit2: Fixed double HotKetSet on restore.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>

;It's not a good idea to set the NOREPEAT flag to True and the NOOVERLAPCALL to False if the function called
;is blocking (e.g: "while" or any dialogbox) as your function will be called until the end of all instances queued.

;these are the flags as in Yashied's HotKey UDF
Global $blOptHotKey_NOREPEAT = True, $blOptHotKey_NOOVERLAPCALL = True
;the flag NOBLOCKHOTKEY is the purpose of this example so there is no option for it

;when the GUI is minimized, this last does not receive the "unactivated" WM, we need to catch the syscommand WM.
Global $blGUIMinimized = False

_Main()

Func _Main()
    Local $hGUI = GUICreate("GUI")
    GUIRegisterMsg($WM_ACTIVATE, "WM_ACTIVATE")
    GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
    GUISetState()

    While GUIGetMsg() <> $GUI_EVENT_CLOSE
        Sleep(10)
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>_Main

;call this function when the GUI is un/activated
Func WM_ACTIVATE($hWnd, $iMsg, $iwParam, $ilParam)
    If $iwParam And Not $blGUIMinimized Then ;hWnd activated
        _HotKey_Enable()
    Else
        _Hotkey_Disable()
    EndIf

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_ACTIVATE

;call this function when the GUI receives a system command
Func WM_SYSCOMMAND($hWnd, $iMsg, $wParam, $lParam)
    Local Const $SC_MINIMIZE = 0xF020, $SC_RESTORE = 0xF120

    Switch BitAND($wParam, 0xFFF0)
        Case $SC_MINIMIZE
            _Hotkey_Disable()
            $blGUIMinimized = True
        Case $SC_RESTORE
            $blGUIMinimized = False
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SYSCOMMAND

;sets the hotkey
Func _HotKey_Enable()
    HotKeySet("{F1}", "_Help")
EndFunc   ;==>_HotKey_Enable

;releases the hotkey
Func _Hotkey_Disable()
    HotKeySet("{F1}")
EndFunc   ;==>_Hotkey_Disable

Func _Help()
    If $blOptHotKey_NOOVERLAPCALL Then
        Local Static $blFuncFinished = True ;defined for the first call
        If Not $blFuncFinished Then Return ;the function is already called but not complete

        $blFuncFinished = False
    EndIf

    If $blOptHotKey_NOREPEAT Then
        While _IsPressed("70") ;F1 key
            Sleep(10)
        WEnd
    EndIf

    ConsoleWrite("What can I do for you? Time is now: " & @HOUR & ":" & @MIN & ":" & @SEC & ":" & @MSEC & @CRLF)

    ;demonstrates the NOOVERLAPCALL flag
    Local $iTimer = TimerInit()
    While TimerDiff($iTimer) < 2000
        Sleep(10)
    WEnd

    If $blOptHotKey_NOOVERLAPCALL Then
        ;sets the function as completed for the next call
        $blFuncFinished = True
    EndIf
EndFunc   ;==>_Help
Edited by FireFox
Posted

Here a function to find a solution using + - * / as operants.

Example: 11 5 3 = 9 -> 11-5+3=9

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <Array.au3>

Global $aOp[4] = ["+","-","*","/"]
Global $sTest = "11,,5,,3,=,9"

Global Const $hGUI = GUICreate("Math Resolver beta build 2013-02-27 by UEZ", 532, 138, -1, -1)
GUISetFont(12, 400, 0, "Arial")
GUISetBkColor(0xC0DCC0)
Global Const $iOperants = GUICtrlCreateLabel("Operants", 10, 12, 68, 22)
Global Const $iInputOperants = GUICtrlCreateInput("+ - * /", 80, 8, 52, 26, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY))
Global Const $iTerm = GUICtrlCreateLabel("Term", 40, 52, 40, 22)
Global Const $iInputTerm = GUICtrlCreateInput($sTest, 80, 48, 361, 26)
Global Const $iResult = GUICtrlCreateLabel("Result", 30, 100, 47, 22)
Global Const $iInputResult = GUICtrlCreateInput("", 80, 96, 361, 26, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY))
Global Const $iResolve = GUICtrlCreateButton("Resolve", 448, 96, 75, 25)
GUICtrlSetFont(-1, 11, 400, 0, "Arial")
ControlFocus($hGUI, "", $iResolve)
GUISetState(@SW_SHOW)

Global $aMath

Do
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIDelete()
            Exit
        Case $iResolve
            If Not StringRegExp(GUICtrlRead($iInputTerm), "(\d+,,\d+),=,\d+", 0) Then
                MsgBox(16 + 262144, "ERROR", "Please check the term and try again!", 30)
                ContinueLoop
            EndIf
            $aMath = StringSplit(GUICtrlRead($iInputTerm) , ",", 2)
            GUICtrlSetData($iInputResult, BruteForce_Solver($aMath, $aOp))
    EndSwitch
Until False

Func BruteForce_Solver($aMath, $aOp, $bCheckAll = False)
    Local $aInit = $aMath ;save original array
    Local $sString = StringStripWS(_ArrayToString($aMath, ","), 8)
    Local Const $iPosEqual = StringInStr($sString, "=") ;calculate = position
    If $iPosEqual < 6 Then Return SetError(1, 0, $aInit)
    Local Const $iCount = StringReplace($sString, ",,", ",,")
    If Not @extended Then Return SetError(2, 0, "Term Error")
    Local $aTmp[@extended] ;create an array with count of placeholders for operants
    Local Const $iMax = UBound($aOp) ^ (UBound($aTmp)) ;calculate all posible combinations
    Local $i, $j = 0, $k = 0, $l, $sAll, $sCompacted
    Do
        For $i = 0 To UBound($aTmp) - 1 ;fill combination of operants index to the array
            $aTmp[$i] = Mod(Int($j / (2^$k)), UBound($aOp))
            $k += 2
        Next
        $l = 0
        $i = 0
        Do
            $aMath[$l + 1] = $aOp[$aTmp[$l / 2]] ;insert operants according to operants index array
            $l += 2
            $i += 1
        Until $i = UBound($aTmp)
        $sString = _ArrayToString($aMath, "")
        If Execute($sString) Then ;check equation
            $sCompacted = StringStripWS($sString, 8)
            If $bCheckAll Then
                $sAll &= $sCompacted & ", " ;save all solutions
            Else
                Return $sCompacted ;if equation is true than we found at least 1 solution
            EndIf
        EndIf
        $k = 0
        $j += 1
    Until $j = $iMax
    If $bCheckAll And $sAll <> "" Then Return StringTrimRight($sAll, 2)
    Return SetError(3, 0, "Not resolvable") ;otherwise term not solvable
EndFunc

It uses the brute force method to find a solution if available. I hope it's bug free.

Br,

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

  • 3 weeks later...
Posted

I like this entertainment.

This is your script with Reset button to create the new task without force.

Type any correct expression into Result field and press Reset.

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <Array.au3>
;Add by ValeryVal
; - Reset button

Global $aOp[4] = ["+","-","*","/"]
Global $sTest = "11,,5,,3,=,9"

Global Const $hGUI = GUICreate("Math Resolver beta build 2013-02-27 by UEZ", 532, 138, -1, -1)
GUISetFont(12, 400, 0, "Arial")
GUISetBkColor(0xC0DCC0)
Global $iOperants = GUICtrlCreateLabel("Operants", 10, 12, 100, 22)
Global $iInputOperants = GUICtrlCreateInput("+ - * /", 110, 8, 330, 26, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY))
Global $iTerm = GUICtrlCreateLabel("Term", 10, 52, 100, 22)
Global $iInputTerm = GUICtrlCreateInput($sTest, 110, 48, 330, 26)
Global $iReSet = GUICtrlCreateButton("Reset", 448, 48, 75, 25)
GUICtrlSetTip($iReSet, 'Create new task from Result content!')
Global $iResult = GUICtrlCreateLabel("Result", 10, 100, 100, 22)
Global $iInputResult = GUICtrlCreateInput("", 110, 96, 330, 26)
Global $iResolve = GUICtrlCreateButton("Resolve", 448, 96, 75, 25)
GUICtrlSetTip($iInputResult, 'You can type any simple expression here!')
GUICtrlSetFont(-1, 11, 400, 0, "Arial")
ControlFocus($hGUI, "", $iResolve)
GUISetState(@SW_SHOW)

Global $aMath

Do
Switch GUIGetMsg()
     Case $GUI_EVENT_CLOSE
         GUIDelete()
         Exit
     Case $iResolve
         If Not StringRegExp(GUICtrlRead($iInputTerm), "(\d+,,\d+),=,\d+", 0) Then
             MsgBox(16 + 262144, "ERROR", "Please check the term and try again!", 30)
             ContinueLoop
         EndIf
         $aMath = StringSplit(GUICtrlRead($iInputTerm) , ",", 2)
         GUICtrlSetData($iInputResult, BruteForce_Solver($aMath, $aOp))
     Case $iReSet
         $sTest = StringStripWS(GUICtrlRead($iInputResult), 8)
         if $sTest then
             $iPos = StringInStr($sTest,"=")
             if $iPos then
             $sTest = StringTrimRight($sTest,StringLen($sTest)-StringInStr($sTest,"=")+1)
             endif
             $sTest = $sTest & ",=," & Execute($sTest)
             for $i = 0 to 3
             $sTest = StringReplace($sTest,$aOp[$i],",,")
             next
             GUICtrlSetData($iInputTerm,$sTest)
             GUICtrlSetData($iInputResult,"")
         endif
EndSwitch
Until False

Func BruteForce_Solver($aMath, $aOp, $bCheckAll = False)
Local $aInit = $aMath ;save original array
Local $sString = StringStripWS(_ArrayToString($aMath, ","), 8)
Local Const $iPosEqual = StringInStr($sString, "=") ;calculate = position
If $iPosEqual < 6 Then Return SetError(1, 0, $aInit)
Local Const $iCount = StringReplace($sString, ",,", ",,")
If Not @extended Then Return SetError(2, 0, "Term Error")
Local $aTmp[@extended] ;create an array with count of placeholders for operants
Local Const $iMax = UBound($aOp) ^ (UBound($aTmp)) ;calculate all posible combinations
Local $i, $j = 0, $k = 0, $l, $sAll, $sCompacted
Do
     For $i = 0 To UBound($aTmp) - 1 ;fill combination of operants index to the array
         $aTmp[$i] = Mod(Int($j / (2^$k)), UBound($aOp))
         $k += 2
     Next
     $l = 0
     $i = 0
     Do
         $aMath[$l + 1] = $aOp[$aTmp[$l / 2]] ;insert operants according to operants index array
         $l += 2
         $i += 1
     Until $i = UBound($aTmp)
     $sString = _ArrayToString($aMath, "")
     If Execute($sString) Then ;check equation
         $sCompacted = StringStripWS($sString, 8)
         If $bCheckAll Then
             $sAll &= $sCompacted & ", " ;save all solutions
         Else
             Return $sCompacted ;if equation is true than we found at least 1 solution
         EndIf
     EndIf
     $k = 0
     $j += 1
Until $j = $iMax
If $bCheckAll And $sAll <> "" Then Return StringTrimRight($sAll, 2)
Return SetError(3, 0, "Not resolvable") ;otherwise term not solvable
EndFunc

Enjoy!

:shifty:

The point of world view

Posted (edited)

Create a transparent edit control from this example.

#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3> ;required for: $GUI_EVENT_CLOSE
#include <Constants.au3>
#include <WinAPIEx.au3> ;url: http://www.autoitscript.com/forum/topic/98712-winapiex-udf/
#include <Debug.au3> ;required for: _Assert

#region Global Vars
Global Const $WM_APP_REDRAWWINDOW = $WM_APP + 1

Global $_hBrushBack = 0, $_hBitmapBack = 0, $_pfnDefEditProc = 0

Global Const $_sBkBitmapFullPath = @ScriptDir & "\autoit_wall_grey_small.bmp"

Local $hNew_WndProc = DllCallbackRegister("_MyEdit_Proc", "int", "hwnd;uint;wparam;lparam")
Global $_pNew_WndProc = DllCallbackGetPtr($hNew_WndProc)
#endregion Global Vars

#region GUI
Local Const $hGUI = GUICreate("Demo Transparent Edit Control", 358, 208, -1, -1, BitOR($DS_MODALFRAME, $WS_POPUP, $WS_CAPTION, $WS_SYSMENU))

Global Const $tbMyEdit = GUICtrlCreateEdit("", 15, 16, 240, 176, BitOR($ES_MULTILINE, $ES_AUTOHSCROLL, $ES_WANTRETURN, $WS_VSCROLL, $WS_HSCROLL))

;~ GUIRegisterMsg($WM_INITDIALOG, "WM_INITDIALOG")
WM_INITDIALOG($hGUI)
GUIRegisterMsg($WM_CTLCOLOREDIT, "WM_CTLCOLOREDIT")
GUIRegisterMsg($WM_ERASEBKGND, "WM_ERASEBKGND")
GUIRegisterMsg($WM_DESTROY, "WM_DESTROY")

GUISetState(@SW_SHOW, $hGUI)
#endregion GUI

#region Loop
While GUIGetMsg() <> $GUI_EVENT_CLOSE
    Sleep(10)
WEnd

GUIDelete($hGUI)
#endregion Loop

#region WM
Func WM_INITDIALOG($hWnd) ;bool
    $_hBitmapBack = _WinAPI_LoadImage(0, $_sBkBitmapFullPath, $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)
    _Assert("$_hBitmapBack <> 0")
    $_hBrushBack = _WinAPI_CreatePatternBrush($_hBitmapBack)
    _Assert("$_hBrushBack <> 0")

    ; Subclass edit control
    Local $hWndEdit = _WinAPI_GetDlgItem($hWnd, $tbMyEdit)
;~     _Assert("$hWndEdit <> 0") ;commented, reason: bug
    $_pfnDefEditProc = _WinAPI_SetWindowLong($hWndEdit, $GWL_WNDPROC, $_pNew_WndProc)

    Return False
EndFunc   ;==>WM_INITDIALOG

Func WM_CTLCOLOREDIT($hWnd, $uMsg, $wParam, $lParam) ;HBRUSH
    Local $hBrush = 0

    Switch $uMsg
        Case $WM_CTLCOLOREDIT
            _WinAPI_SetTextColor($wParam, _WinAPI_SwitchColor(0x800000))
            _WinAPI_SetBkMode($wParam, $TRANSPARENT)
            $hBrush = $_hBrushBack
    EndSwitch

    Return $hBrush
EndFunc   ;==>WM_CTLCOLOREDIT

Func WM_ERASEBKGND($hWnd, $uMsg, $wParam, $lParam) ;bool
    Local $tRect = _WinAPI_GetClientRect($hWnd)
    Local $hOldBrush = _WinAPI_SelectObject($wParam, $_hBrushBack)
    _WinAPI_PatBlt($wParam, 0, 0, DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left"), DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top"), $PATCOPY)
    _WinAPI_SelectObject($wParam, $hOldBrush)

    Return True
EndFunc   ;==>WM_ERASEBKGND

Func WM_DESTROY($hWnd, $uMsg, $wParam, $lParam) ;void
    _WinAPI_DeleteObject($_hBitmapBack)
    _WinAPI_DeleteObject($_hBrushBack)
EndFunc   ;==>WM_DESTROY
#endregion WM

Func _MyEdit_Proc($hWnd, $uMsg, $wParam, $lParam) ;LRESULT CALLBACK
    Switch $uMsg
        Case $WM_VSCROLL, $WM_HSCROLL, $WM_MOUSEWHEEL, $WM_KEYDOWN
            _WinAPI_PostMessage($hWnd, $WM_APP_REDRAWWINDOW, $hWnd, 0)
        Case $WM_APP_REDRAWWINDOW
            Return _MyEdit_OnRedrawWindow($wParam, $lParam)
    EndSwitch

    Return _WinAPI_CallWindowProc($_pfnDefEditProc, $hWnd, $uMsg, $wParam, $lParam)
EndFunc   ;==>_MyEdit_Proc

Func _MyEdit_OnRedrawWindow($wParam, $lParam) ;HRESULT
    Local $uFlags = BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_ERASE)

    _WinAPI_RedrawWindow($wParam, 0, 0, $uFlags)

    Return 0
EndFunc   ;==>_MyEdit_OnRedrawWindow

Func _WinAPI_CreatePatternBrush($hbmp) ;int
    ;By ProgAndy
    Local $brush = DllCall("gdi32.dll", "long", "CreatePatternBrush", "long", $hbmp)
    If Not @error Then Return $brush[0]

    Return 0
EndFunc   ;==>_WinAPI_CreatePatternBrush
Preview :

561.jpg

autoit_wall_grey_small.bmp

Edited by FireFox
  • 2 weeks later...
Posted (edited)

; #FUNCTION# ;=================================================================================
; Name...........: _StringSplitRegExp
; Description ...: Split a string according to a regular expression.
; Syntax.........: _StringSplitRegExp($sString, $sPattern[, $flag = 0[, $sIncludeMatch = 0[, $iCount = 0]]])
; Parameters ....: $sString - String: String to split.
;           $sPattern - String: Regular expression to split on.
;           $flag - return count in the first element 
;           $sIncludeMatch -
;                   |0 - To exclude a divider (by default)
;                   |1 - To attach a divider at the left
;                   |2 - To attach a divider on the right
;                   $iCount - The number of times to execute the replacement in the string
; Return values .: Success - Array: Array of substrings, the total is in $array[0].
;           Failure - Array: The count is 1 ($array[0]) and the full string is returned ($array[1]) and sets @error:
;                   |1 No suitable placeholder delimiter could be constructed.
;                   |2 Bad RegExp pattern, @extended contains the offset of the error in the pattern.
;                   |3 Delimiter not found.
; Author ........: AZJIO, weaponx, dany
; ============================================================================================
; Имя функции ...: _StringSplitRegExp
; Описание ........: Разделяет строки с помощью регулярного выражения
; Синтаксис.......: _StringSplitRegExp($sString, $sPattern[, $flag = 0[, $sIncludeMatch = 0[, $iCount = 0]]])
; Параметры:
;           $sString - Строка для деления на части
;           $sPattern - Регулярное выражение определяющая строку, которая будет разделителем
;           $flag - По умолчанию 0 - возвращает количество элементов в первый элемент массива, иначе не возвращает
;           $sIncludeMatch - Включить раздедитель в результат
;                   |0 - Исключить разделитель (по умолчанию)
;                   |1 - Разделитель присоединять слева
;                   |2 - Разделитель присоединять справа
;       $iCount - количество выполненных замен
; Возвращаемое значение: Успешно - Массив строк, в котором $array[0] содержит количество строк в массиве
;           Неудачно - Массив в котором исходная строка помещается в $array[1], и устанавливает @error:
;                   |0 - нет ошибок
;                   |1 - Внутренняя ошибка, не удалось выбрать подстановочный разделитель
;                   |2 - Регулярное выражение содержит ошибку
;                   |3 - Регулярное выражение не находит разделитель в строке
; Автор ..........: AZJIO, weaponx, dany
; ============================================================================================
; http://www.autoitscript.com/forum/topic/139260-autoit-snippets/?p=1065198
; http://www.autoitscript.com/forum/topic/139260-autoit-snippets/page__st__140#entry1036931
; http://www.autoitscript.com/forum/topic/65662-stringsplitregexp/
Func _StringSplitRegExp($sString, $sPattern, $flag = 0, $sIncludeMatch = 0, $iCount = 0)
    Local $sSplit, $sDelim, $sReplace, $Toggle, $iPos = 1
    If IsBinary($sString) Then
        $sString = Hex($sString)
        $sDelim = Chr(1)
        Local $aError[2] = [1, $sString]
    Else
        Local $aError[2] = [1, $sString]
        For $i = 1 To 30
            $Toggle = Not $Toggle
            If $Toggle Then ; 1, 30, 3, 28    ...   27, 4, 29, 2
                $sDelim &= Chr($i)
            Else
                $sDelim &= Chr(32 - $i)
            EndIf
            $iPos = StringInStr($sString, $sDelim, 1, 1, $iPos) ; смещение позволяет найти разделитель за 1 проход
            If Not $iPos Then ExitLoop ; если вхождение не найдено, то разделитель сформирован
        Next
        If $iPos Then Return SetError(1, 0, $aError)
    EndIf
    Switch $sIncludeMatch
        Case 0
            $sReplace = $sDelim
        Case 1
            $sReplace = "$0" & $sDelim
        Case 2
            $sReplace = $sDelim & "$0"
    EndSwitch
    $sSplit = StringRegExpReplace($sString, $sPattern, $sReplace, $iCount)
    If @error Then Return SetError(2, @extended, $aError)
    If Not @extended Then Return SetError(3, 0, $aError)
    If $flag Then $flag = 2
    Return StringSplit($sSplit, $sDelim, 1 + $flag)
EndFunc   ;==>_StringSplitRegExp
#include <Array.au3>

; $sString = 'wd12kh4nb5016vg456yu'
; $Array = _StringSplitRegExp($sString, '\d+')
; _ArrayDisplay($Array, 'Array')

$sString = '<i>Height</i> <b>15</b> <i>Width</i> <b>22</b>'
$Array = _StringSplitRegExp($sString, '(?:\h*</?[ib]>\h*)+')
If @error Then
    MsgBox(0, '', '@error = ' & @error)
Else
    _ArrayDisplay($Array, 'Array')
EndIf


; #FUNCTION# ;=================================================================================
; Name...........: _StringSplitRegExp
; Description ...: Split a string according to a regular expression.
; Syntax.........: _StringSplitRegExp($sString, $sPattern)
; Parameters ....: $sString - String: String to split.
;           $sPattern - String: Regular expression to split on.
; Return values .: Success - Array
;           Failure - sets @error:
;                   |1 - No match
;                   |2 - Wrong template
;                   |3 - The template is not provided excluding groups
; Author ........: AZJIO
; Remarks .......:
; ============================================================================================
; Имя функции ...: _StringSplitRegExp
; Описание ........: Разделяет строки с помощью регулярного выражения
; Синтаксис.......: _StringSplitRegExp($sString, $sPattern)
; Параметры:
;           $sString - Строка для деления на части
;           $sPattern - Регулярное выражение определяющая строку, которая будет разделителем
; Возвращаемое значение: Успешно - Массив строк
;           Неудачно - Устанавливает @error:
;                   |1 - Нет совпадений
;                   |2 - Неправильный шаблон
;                   |3 - В шаблоне не обеспечено исключение групп
; Автор ..........: AZJIO
; Примечания ..: Особенность такого подхода - все группы в патерне должны быть исключены из поиска методом ?:
; ============================================================================================
Func _StringSplitRegExp($sString, $sPattern)
    If StringRegExp(StringRegExpReplace($sPattern, '\\.', ''), '\((?!\?(?:<!|<=|=|!|:|>))') Then Return SetError(3)
    Local $aSplit = StringRegExp($sString, '(?s)(.*?)(?:' & $sPattern & '|\z)', 3)
    ; Local $aSplit = StringRegExp($sString, '(?s)(.*?' & $sPattern & '|.*?\z)', 3)
    If @error Then Return SetError(@error)
    If UBound($aSplit) > 1 Then ReDim $aSplit[UBound($aSplit)-1]
    Return $aSplit
EndFunc   ;==>_StringSplitRegExp

Edited by AZJIO
Posted (edited)

;rounds a size to the nearest font size:
;0, 0.25, 0.5, 0.75, 1

;Mat's version
Func _RoundToFontSize($iSize)
    Return Round($iSize*4)/4
EndFunc

Func _RoundToFontSize($iSize)
    Local Const $iSizeInt = Int($iSize), $iDecimal = $iSize - $iSizeInt
    Local $iFontRound = 1

    Select
        Case $iDecimal <= .125
            $iFontRound = 0
        Case $iDecimal < .375
            $iFontRound = .25
        Case $iDecimal <= .625
            $iFontRound = .5
        Case $iDecimal < .875
            $iFontRound = .75
    EndSelect

    Return $iSizeInt + $iFontRound
EndFunc   ;==>_RoundToFontSize

Edited by FireFox
  • 2 months later...
Posted (edited)

For above, you could just use Round($iSize*4)/4
 
I've just cleared out a huge directory of test scripts (120 of them!), but I found a couple of little snippets I didn't realise I had. This is a simple Damerau–Levenshtein string matching test. It works best on longer strings when characters are switched, missed or added, with the MVP names I've used for an example below, entering "Xeno" will match "UEZ" rather than "Xenobiologist".

String distance is literally the number of changes you'd have to make to transform the string. "Xeno" to "UEZ" is only 3, as you delete the O and change 2 characters (comparisons are case insensitive)
 

#include <Math.au3>


Local $asMVPs[27] = [ _
        "AdmiralAlkex", _
        "BrewManNH", _
        "DaleHohm", _
        "FireFox", _
        "GEOSoft", _
        "guinness", _
        "James", _
        "jchd", _
        "JLogan3o13", _
        "KaFu", _
        "kylomas", _
        "Manadar", _
        "martin", _
        "Mat", _
        "MHz", _
        "monoceres", _
        "MrCreatoR", _
        "ptrex", _
        "TheSaint", _
        "UEZ", _
        "Valuater", _
        "water", _
        "wraithdu", _
        "Xenobiologist", _
        "Yashied", _
        "YogiBear", _
        "Zedna" _
    ]


Local $sTest = "DelaHom"

MsgBox(0, $sTest, $asMVPs[_String_ClosestMatch($sTest, $asMVPs)])


Func _String_ClosestMatch($sInput, $asOptions)
    If Not IsArray($asOptions) And UBound($asOptions, 0) <> 1 Then Return SetError(1, 0, 0)

    Local $iMinLen = -1, $iMinInd = -1, $d

    For $i = 0 To UBound($asOptions) - 1
        $d = _String_Distance($sInput, $asOptions[$i])

        ConsoleWrite($asOptions[$i] & @TAB & " - " & $d & @LF)

        If $iMinLen = -1 Or $d < $iMinLen Then
            $iMinLen = $d
            $iMinInd = $i
        EndIf
    Next

    Return SetExtended($iMinLen, $iMinInd)
EndFunc   ;==>_String_ClosestMatch

; http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance#Algorithm
Func _String_Distance($s, $t)
    Local $m = StringLen($s)
    Local $n = StringLen($t)

    Local $d[$m + 1][$n + 1]

    For $i = 0 To $m
        $d[$i][0] = $i
    Next

    For $j = 0 To $n
        $d[0][$j] = $j
    Next

    Local $cost = 0

    For $j = 1 To $n
        For $i = 1 To $m
            $cost = 1 - Number(StringMid($s, $i, 1) = StringMid($t, $j, 1))
            $d[$i][$j] = _Min($d[$i][$j - 1] + 1, _ ; Insertion
                    _Min($d[$i - 1][$j] + 1, _ ; Deletion
                    $d[$i - 1][$j - 1] + $cost)) ; Substitution

            If $i > 1 And $j > 1 And _
                    StringMid($s, $i, 1) = StringMid($t, $j - 1, 1) And _
                    StringMid($s, $i - 1, 1) = StringMid($t, $j, 1) Then
                $d[$i][$j] = _Min($d[$i][$j], $d[$i - 1][$j - 1] + $cost)
            EndIf
        Next
    Next

    Return $d[$m][$n]
EndFunc   ;==>_String_Distance
Edited by Mat
Posted (edited)

Interesting algorithm.  :think: It remembers me a topic where someone were looking for something like this.

Edited by FireFox
Posted

Another one I found. Not sure what I even used this for though.

Like StringInStr, but it finds the nth occurrence of any one of a range of characters in a string. 

#include <Math.au3>

Local $sIn = "Hello, World!"

ConsoleWrite($sIn & @LF)
ConsoleWrite(_String_CharInStr($sIn, " .,?!", 0, -1) & @LF)

; Same as StringInStr, but searches for any character within $sChars.
; Returns the index of the actual character in @extended
Func _String_CharInStr($sString, $sChars, $iCaseSense = 0, $iOccurence = 1, $iStart = Default, $iCount = Default)
    Local $iRet = -1, $i

    If $iCount = Default Then $iCount = StringLen($sString)
    If $iStart = Default Then
        If $iOccurence < 0 Then
            $iStart = StringLen($sString)
        Else
            $iStart = 1
        EndIf
    EndIf

    Local $iEnd = $iStart + $iCount, $iStep = 1

    If $iOccurence < 0 Then
        $iEnd = $iStart - $iCount
        $iStep = -1
    EndIf

    Local $n = 0, $j
    For $c = $iStart To $iEnd Step $iStep
        $j = StringInStr($sChars, StringMid($sString, $c, 1), $iCaseSense)

        If $j Then
            $n += $iStep

            If $n = $iOccurence Then Return SetExtended($j, $c)
        EndIf
    Next

    If $iRet < 0 Then Return 0
    Return $iRet
EndFunc   ;==>_String_CharInStr
  • 1 month later...
Posted

Improved _ArrayFindAll():

#include <Array.au3> ;For _ArrayFindAll()

#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w- 7

Global $Dim = 10, $Timer, $iPercDiff
Do
    $Dim *= 10
    ; Create an array and fill it with random numbers
    Global $avArray[$Dim]
    For $x = 0 To UBound($avArray) - 1
        $avArray[$x] = Random(0, 5, 1)
    Next
    ConsoleWrite("$avArray[" & UBound($avArray) & "]" & @CRLF)

    ; Get how long _ArrayFindAll() takes
    $Timer = TimerInit()
    Global $aiResult1 = _ArrayFindAll($avArray, 0)
    Global $iTimerDiff1 = TimerDiff($Timer)
    ConsoleWrite("_ArrayFindAll = " & Round($iTimerDiff1, 2) & " ms" & @CRLF)

    ; Get how long _ArrayFindAllFast() takes
    $Timer = TimerInit()
    Global $aiResult2 = _ArrayFindAllFast($avArray, 0)
    Global $iTimerDiff2 = TimerDiff($Timer)
    ConsoleWrite("_ArrayFindAllFast = " & Round($iTimerDiff2, 2) & " ms" & @CRLF)

    ; Display the difference in %
    If $iTimerDiff1 > $iTimerDiff2 Then
        $iPercDiff = Round(($iTimerDiff1 - $iTimerDiff2) / $iTimerDiff1 * 100, 2) & "% faster"
    Else
        $iPercDiff = Round(($iTimerDiff2 - $iTimerDiff1) / $iTimerDiff1 * 100, 2) & "% slower"
    EndIf
    ConsoleWrite("_ArrayFindAllFast() is " & $iPercDiff & " than _ArrayFindAll()" & @CRLF & @CRLF)
Until $Dim = 1000000

Func _ArrayFindAllFast(Const ByRef $avArray, $vValue, $iStart = 0, $iEnd = 0, $iCase = 0, $iCompare = 0, $iForward = 1, $iSubItem = -1)
    If Not IsArray($avArray) Then Return SetError(1, 0, -1)
    If UBound($avArray, 0) > 2 Or UBound($avArray, 0) < 1 Then Return SetError(2, 0, -1)

    Local $iUBound = UBound($avArray) - 1

    ; Bounds checking
    If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound
    If $iStart < 0 Then $iStart = 0
    If $iStart > $iEnd Then Return SetError(4, 0, -1)

    ; Direction (flip if $iForward = 0)
    Local $iStep = 1
    If Not $iForward Then
        Local $iTmp = $iStart
        $iStart = $iEnd
        $iEnd = $iTmp
        $iStep = -1
    EndIf

    ; same var Type of comparison
    Local $iCompType = False
    If $iCompare = 2 Then
        $iCompare = 0
        $iCompType = True
    EndIf

    Local $aiFoundData
    ; Search
    Switch UBound($avArray, 0)
        Case 1 ; 1D array search
            If Not $iCompare Then
                If Not $iCase Then
                    For $i = $iStart To $iEnd Step $iStep
                        If $iCompType And VarGetType($avArray[$i]) <> VarGetType($vValue) Then ContinueLoop
                        If $avArray[$i] = $vValue Then $aiFoundData &= "|" & $i
                    Next
                Else
                    For $i = $iStart To $iEnd Step $iStep
                        If $iCompType And VarGetType($avArray[$i]) <> VarGetType($vValue) Then ContinueLoop
                        If $avArray[$i] == $vValue Then $aiFoundData &= "|" & $i
                    Next
                EndIf
            Else
                For $i = $iStart To $iEnd Step $iStep
                    If StringInStr($avArray[$i], $vValue, $iCase) > 0 Then $aiFoundData &= "|" & $i
                Next
            EndIf
        Case 2 ; 2D array search
            Local $iUBoundSub = UBound($avArray, 2) - 1
            If $iSubItem > $iUBoundSub Then $iSubItem = $iUBoundSub
            If $iSubItem < 0 Then
                ; will search for all Col
                $iSubItem = 0
            Else
                $iUBoundSub = $iSubItem
            EndIf

            For $j = $iSubItem To $iUBoundSub
                If Not $iCompare Then
                    If Not $iCase Then
                        For $i = $iStart To $iEnd Step $iStep
                            If $iCompType And VarGetType($avArray[$i][$j]) <> VarGetType($vValue) Then ContinueLoop
                            If $avArray[$i][$j] = $vValue Then $aiFoundData &= "|" & $i
                        Next
                    Else
                        For $i = $iStart To $iEnd Step $iStep
                            If $iCompType And VarGetType($avArray[$i][$j]) <> VarGetType($vValue) Then ContinueLoop
                            If $avArray[$i][$j] == $vValue Then $aiFoundData &= "|" & $i
                        Next
                    EndIf
                Else
                    For $i = $iStart To $iEnd Step $iStep
                        If StringInStr($avArray[$i][$j], $vValue, $iCase) > 0 Then $aiFoundData &= "|" & $i
                    Next
                EndIf
            Next
        Case Else
            Return SetError(7, 0, -1)
    EndSwitch
    If $aiFoundData <> "" Then
        Return StringSplit(StringTrimLeft($aiFoundData, 1), "|", 2)
    Else
        Return SetError(6, 0, -1)
    EndIf
EndFunc   ;==>_ArrayFindAllFast

"Just be fred, all we gotta do, just be fred."  -Vocaliod

"That is a Hadouken. A KAMEHAMEHA would have taken him 13 days and 54 episodes to form." - Roden Hoxha

@tabhooked

Clock made of cursors ♣ Desktop Widgets ♣ Water Simulation

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...