seadoggie01 Posted October 9, 2019 Share Posted October 9, 2019 (edited) 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 expandcollapse popup#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 December 1, 2021 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 functionsAcro.au3 UDF - Automating Acrobat ProToDo Finder - Find #ToDo: lines in your scriptsUI-SimpleWrappers UDF - Use UI Automation more Simply-erKeePass UDF - Automate KeePass, a password managerInputBoxes - Simple Input boxes for various variable types Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now