Jump to content

Wildcard Search


seadoggie01
 Share

Recommended Posts

I imagine someone's done this before, but I couldn't find it. I was trying to find a program without searching through lots of folders and attempted to use multiple wildcards, when I realized it wasn't possible.

Specifically, I was trying to find Adobe Acrobat, but it's located in different places depending on the computer... so this works to find it now: WildcardSearch("C:\Program Files*\Adobe\*\*\Acrobat.exe") It can be in either Program Files directory with \Adobe\<AcobatVersion>\Acrobat\Acrobat.exe and the Acrobat version varies. Ugh :)

(Known) Restrictions:

  • Wildcards are only supported at the end ("C:\Program Files*\" matches "C:\Program Files\" and "C:\Program Files (x86)\") Fixed!
  • Wildcards cannot represent backslashes, so you have to know the level of the file
  • Supports asterisks and question marks
#include <Array.au3>    ; Only for _ArrayDisplay

_ArrayDisplay(_Wildcard_Search("U:\*\1\*\3\*\5\*\7\*\9\"), "Search Results...")
_ArrayDisplay(_Wildcard_Search("U:\*\1\*\3\*\5\*\7\*\9\*"), "Search Results...")
_ArrayDisplay(_Wildcard_Search("U:\*\1\*\3\*\5\*\7\*\*9*\*"), "Search Results...")

; No, it's not from anywhere. I made it up.
Global Enum $PATH_TYPE_FILES = 1, _
            $PATH_TYPE_FOLDERS = 2, _
            $PATH_TYPE_BOTH = 3

; #FUNCTION# ====================================================================================================================
; Name ..........: _Wildcard_Search
; Description ...: Searches a path and expands *'s as needed
; Syntax ........: _Wildcard_Search($sSearch)
; Parameters ....: $sSearch             - a string value.
;                  $iPathType           - [optional] an integer value. Default is $PATH_TYPE_FILES
; Return values .: Success - 0-based 1D array of files and/or dirs
;                  Failure - False and sets @error:
;                  |1 - Final character is a backslash, nothing will match: add a trailing * or remove it.
; Author ........: Seadoggie
; Modified ......: December 1, 2021
; Remarks .......: * doesn't match backslashes, meaning that multiple directories will only be searched like *\*
;                  | and the depth of the search must be known before starting
;                  Uses a breadth first search
;                  Note that only one * is allowed per folder/file, uses FileFindFirst/NextFile internally
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _Wildcard_Search($sSearch, $iPathType = Default)

    If IsKeyword($iPathType) Then $iPathType = $PATH_TYPE_FILES

    ; If the trailing character is a backslash
    If StringRight($sSearch, 1) = "\" Then
        ; If the user doesn't want folders
        If Not BitAND($iPathType, $PATH_TYPE_FOLDERS) = $PATH_TYPE_FOLDERS Then
            ; Nothing will match
            Return SetError(1, 0, False)
        Else
            ; Remove the trailing backslash
            $sSearch = StringTrimRight($sSearch, 1)
        EndIf
    EndIf

    Local $aFolders = StringSplit($sSearch, "\", 3)
    Local $tempOptions[0], $aNewOptions[0]
    Local $aResults[1], $sFile
    ; For each wildcard
    For $i = 0 To UBound($aFolders) - 1
        ; For each result
        For $z = 0 To UBound($aResults) - 1
            $sFile = $aResults[$z] & $aFolders[$i]
            ; If there is a wildcard
            If StringInStr($aFolders[$i], "*") <> 0 Then
                ; Search with the added section
                $aNewOptions = __SearchToArray($sFile, ($i = UBound($aFolders) - 1 ? $iPathType : $PATH_TYPE_FOLDERS))
                ; If the search completed then
                If Not @error Then _ArrayConcatenate($tempOptions, $aNewOptions)
            Else
                If StringInStr(FileGetAttrib($sFile), "D") = 0 Then
                    ; If the user wants files Then keep it
                    If BitAND($iPathType, $PATH_TYPE_FILES) = $PATH_TYPE_FILES Then
                        _ArrayAdd($tempOptions, $sFile)
                        Debug("User wants files!?")
                    EndIf
                Else
                    Debug("Folder: " & $sFile)
                    ; If we aren't at the final folder
                    If $i < UBound($aFolders) - 1 Then
                        ; Keep the folder, we'll search inside it
                        _ArrayAdd($tempOptions, $sFile & "\")
                    ElseIf BitAND($iPathType, $PATH_TYPE_FOLDERS) = $PATH_TYPE_FOLDERS Then
                        ; The user wants folder results
                        _ArrayAdd($tempOptions, $sFile & "\")
                    EndIf
                EndIf
            EndIf
        Next
        ; Get all the new options (old options will be missing pieces, so drop them)
        $aResults = $tempOptions
        ; Clear the temp options
        Dim $tempOptions[0]
    Next
    Return $aResults
EndFunc   ;==>_Wildcard_Search

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name ..........: __SearchToArray
; Description ...: Returns array of items, error 1 if search failed, error 2 if empty folder
; Syntax ........: __SearchToArray($sSearch)
; Parameters ....: $sSearch             - a string value.
;                  $iPathType           - an integer value.
; Return values .: Success - 0-based 1D array of matching files
;                : Failure - False and sets @error:
;                | 1 -
; Author ........: Seadoggie
; Modified ......: December 1, 2021
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func __SearchToArray($sSearch, $iPathType)

    ; Get the base folder: Everything to the left of the last '\'
    Local $sBase = StringLeft($sSearch, StringInStr($sSearch, "\", 0, -1))
    ; Remove the base from the search
    $sSearch = StringReplace($sSearch, $sBase, "")

    Local $iErr = 0, $aResults[0]
    ; Search for it
    Local $hSearch = FileFindFirstFile($sBase & $sSearch)
    ; If the search failed
    If $hSearch = -1 Then
        $iErr = 1 + @error ; FileFindFirstFile Returns 1 with an empty folder
    Else
        ; Get the first file/dir
        Local $sResult = FileFindNextFile($hSearch)
        ; For each file found
        While $sResult <> ""
            If StringInStr(FileGetAttrib($sBase & $sResult), "D") = 0 Then
                If BitAND($iPathType, $PATH_TYPE_FILES) = $PATH_TYPE_FILES Then _ArrayAdd($aResults, $sBase & $sResult)
            Else
                If BitAND($iPathType, $PATH_TYPE_FOLDERS) = $PATH_TYPE_FOLDERS Then _ArrayAdd($aResults, $sBase & $sResult & "\")
            EndIf
            ; Get the next file/dir
            $sResult = FileFindNextFile($hSearch)
        WEnd
    EndIf
    ; Close the search
    FileClose($hSearch)
    Return SetError($iErr, 0, $aResults)
EndFunc   ;==>__SearchToArray

Edit (Oct 9, 2020): Now I see that the 'start' will find the program for me. Welp.

Edit 2 (Oct 9, 2020): Support for asterisks anywhere!

Edit 3 (Dec 1, 2021): Speed improvements, simplification, and Files/Folders/Both option

Edited by seadoggie01

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Spoiler

My Humble Contributions:
Personal Function Documentation - A personal HelpFile for your functions
Acro.au3 UDF - Automating Acrobat Pro
ToDo Finder - Find #ToDo: lines in your scripts
UI-SimpleWrappers UDF - Use UI Automation more Simply-er
KeePass UDF - Automate KeePass, a password manager
InputBoxes - Simple Input boxes for various variable types

Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

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