AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Parameters and switches parser

 
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Yook



Joined: 20 Nov 2008
Posts: 64
Location: Thionville, France

PostPosted: Sun Nov 08, 2009 5:12 pm    Post subject: Parameters and switches parser Reply with quote

EDIT : fixed some bugs, added some functionality. You may also want to check Tuncay's Simple Parameter Parser Library

Hi,
I wrote 2 parsing functions to retrieve parameters and to parse switches passed to a script.

An example is included in the script, you can try with the following command line (replace Autohotkey.exe and scriptname.ahk by their full path) :
Autohotkey.exe scriptname.ahk file1 /sw1 /sw2:c:\documents:param2 file2

The parameters passed to the script must match the following rules :

Non-switch-parameters, e.g. file paths, must be enclosed in quotes if they contain spaces. They will be saved in the order in which they appear.
Switches can be placed before, inbetween or after the non-switch-parameters, their order doesn't matter.
Switches can be indicated either with '-' or '/'. their subparameters must be separated by ':'
Example :
/i /time:5:10 -date:11:08:2009
File paths will be parsed correctly even if they contain DRIVELETTER:\ pattern
Example :
/WorkingDir:M:\Documents\
If a parameter contains spaces, the spaces must be enclosed in quotes
Example :
/AHKDir:"C:\Program Files\AutoHotkey\" OR /AHKDir:C:\Program" "Files\AutoHotkey\
Code:
/*
NbParams := GetParams(ParamArrayName[, MaxParams = ""])

   Retrieves the non-switch-parameters (i.e the parameters not starting with a '-' or a '/') into an array :

   ParamArrayName : string or variable containing a string that will be used as a prefix for an array containing the parameters : %ParamArrayName%1 contains 1st param, %ParamArrayName%2 contains 2nd, etc. %ParamArrayName%0 will contain the number of items found.
   MaxParams : the maximum number of parameters that should be saved into the array.

   returns : the number of parameters found (same as %ParamArrayName%0)



NbSubparams := GetSwitch(Switch[, CaseSens = 0, SubparamArrayName = "", MaxSubparams = "", FistParseChar = ":", ParseChar = ""])

   Detects a switch and optionally retrieve its subparameters (e.g. /sw1:SubParam1:SubParam2) into an array :

   Switch : name of the switch (without - or / prefix), can be a Perl-compatible regular expression (PCRE) WITHOUT pattern options.
   CaseSens : Set this to 1 if you want the switch detection to be case sensitive
   SubparamArrayName : string or variable containing a string that will be used as a prefix for an array containing the subparameters : %SubparamArrayName%1 contains 1st param, %SubparamArrayName%2 contains 2nd, etc. %SubparamArrayName%0 will contain the number of items found.
   MaxSubparams : the maximum number of sub parameters that should be saved into the array. If set to -1, the whole string of sub parameters will be retrieved.
   FirstParseChar : The character separating the switch from its sub params. Default is ":". It can be empty.
   ParseChar : The character between two sub params. By default, it is set to empty and internally resolves to ":" and will retrieve correctly the paths (e.g "c:\program files" won't be split into "c" and "\program file"). If explicitly set to ":" or any other char, the paths will be split as well.

   returns :    0 if the switch was not found ;
            -1 if the switch was found but no parameters ;
            the number of subparameters found (same as %SubparamArrayName%0)





The parameters passed to the script must match the following rules :

Non-switch-parameters, e.g. file paths, must be enclosed in quotes if they contain spaces. They will be saved in the order in which they appear.
Switches can be placed before, inbetween or after the non-switch-parameters, their order doesn't matter.
Switches can be indicated either with '-' or '/'. their subparameters must be separated by ':'
Example :
/i /time:5:10 -date:11:08:2009
File paths will be parsed correctly even if they contain DRIVELETTER:\ pattern
Example :
/WorkingDir:M:\Documents\
If a parameter contains spaces, the spaces must be enclosed in quotes
Example :
/AHKDir:"C:\Program Files\AutoHotkey\" OR /AHKDir:C:\Program" "Files\AutoHotkey\
*/



GetParams(ParamArrayName, MaxParams = "")
{
   Local Params
   Params = 1
   Loop, %0%
   {
      If RegExMatch(%A_Index%, "S)(?:^[^-/].*)", %ParamArrayName%%Params%)
         Params++
      If ((MaxParams != "") && (Params > MaxParams))
         Break
   }
   Params--
   %ParamArrayName%0 := Params
   Return %Params%
}

GetSwitchParams(SwitchName, CaseSens = 0, ParamArrayName = "", MaxParams = "", FirstParseChar = ":", ParseChar = "")
{
   Local Params, Params1, ParseMode
   Static ParamList
   If !ParamList ;Initializing a variable containing all the parameters passed to the script
   {
      Loop, %0%
         ParamList .= "`n" %A_Index%
      ParamList .= "`n"
   }
   If FirstParseChar
      FirstParseChar := ( InStr("\.*?+[{|()^$", SubStr(FirstParseChar, 1, 1)) ? "\" SubStr(FirstParseChar, 1, 1) : SubStr(FirstParseChar, 1, 1) )
   If (ParamArrayName = "") ;if the switch does not require parameters
   {
      If RegExMatch(ParamList, ( CaseSens ? "\n[-/]" SwitchName "(?:\n|" FirstParseChar "\n)" : "i)\n[-/]" SwitchName "(?:\n|" FirstParseChar "\n)"))
         Return -1
      Else
         Return 0
   }
   If (MaxParams = -1) ;the whole content is extracted
   {
      If RegExMatch(ParamList, ( CaseSens ? "\n[-/]" SwitchName "(?:\n|" FirstParseChar "([^\n]*))" : "i)\n[-/]" SwitchName "(?:\n|" FirstParseChar "([^\n]*))" ), %ParamArrayName%)
      {
         %ParamArrayName%0 = 1
         Return 1
      }
      Else
      {
         %ParamArrayName%0 = 0
         Return 0
      }
   }
   If (ParseChar = "")
   {
      ParseChar := ":"
      ParseMode := -2 ;test for files
   }
   Else
   {
      ParseChar := ( InStr("\.*?+[{|()^$", SubStr(ParseChar, 1, 1)) ? "\" SubStr(ParseChar, 1, 1) : SubStr(ParseChar, 1, 1) )
      ParseMode := -3 ;don't test for files
   }
   If RegExMatch(ParamList, ( CaseSens ? "\n[-/]" SwitchName "(?:\n|" FirstParseChar "([^" ParseChar "\n]*(" ParseChar "[^" ParseChar "\n]*)*))" : "i)\n[-/]" SwitchName "(?:\n|" FirstParseChar "([^" ParseChar "\n]*(" ParseChar "[^" ParseChar "\n]*)*))" ) , Params )
   {
      If !(Params1)
      {
         %ParamArrayName%0 = 0
         Return -1 ;switch found but no subparams
      }
      Params = 0
      Loop, Parse, Params1, % ( SubStr(ParseChar, 1, 1) = "\" ?  SubStr(ParseChar, 2) : ParseChar )
      {
         Params++
         If ((ParseMode = -2) && RegExMatch(A_LoopField, "^\\")) ;Managing paths containing LETTER:\..., as they will otherwise be parsed at ":"
         {
            Params--
            If RegExMatch(%ParamArrayName%%Params%, "^[A-Za-z]$")
               %ParamArrayName%%Params% .= ":" A_LoopField
            Else If ((MaxParams != "") && (Params >= MaxParams))
               Break
            Else
            {
               Params++
               %ParamArrayName%%Params% := A_LoopField
            }
         }
         Else If ((MaxParams != "") && (Params > MaxParams))
         {
            Params--
            Break
         }
         Else
            %ParamArrayName%%Params% := A_LoopField
      }
      %ParamArrayName%0 := Params
      Return %Params%
   }
   Else
      Return 0
}



;
;
;Example : try command line : Autohotkey.exe scriptname.ahk file1 /sw1 /sw2:c:\documents:param2 file2
;
;



;retrieve the non-switch parameters
GetParams("File")

;Help dialogbox : in this case there must be at least one non-switch parameter
If (!file1 || GetSwitchParams("(h(elp|)|\?)"))
{
   MsgBox, , PROGRAMNAME [%A_ScriptName%], PROGRAMNAME help :`ncommand : %A_ScriptName% [param1 [param2|/sw1] [/sw2]] [/h]`nParam1:`n%A_Tab%Relative or absolute path and name of file to proceed.`n%A_Tab%Should be enclosed in quotes if containing spaces.`nSwitches :`n%A_Tab%/h :%A_Tab%Displays this help.`n%A_Tab%/sw1 :%A_Tab%Proceeds script in a way.`n%A_Tab%/sw2:option1:option2:... :`n%A_Tab%%A_Tab%Proceeds script in another way.
;   ExitApp
}

;Simple switch
If GetSwitchParams("sw1")
   MsgBox sw1 was used.

;Switch with subparameters
If GetSwitchParams("sw2", 0, "sw2_")
{
   If %sw2_0%
   {
      msg = sw2 was used, with parameters :
      Loop, %sw2_0%
         msg .= "`n'" sw2_%A_Index% "'"
   }
   Else
      msg = sw2 was used with no parameters.
   msgbox %msg%
}

msg = Number of files : %File0%`n
Loop, %File0%
   msg .= "file" A_Index " : '" File%A_Index% "'`n"
msgbox %msg%


Last edited by Yook on Sat May 01, 2010 5:32 pm; edited 6 times in total
Back to top
View user's profile Send private message
majkinetor



Joined: 24 May 2006
Posts: 4250
Location: Belgrade

PostPosted: Mon Nov 09, 2009 10:08 am    Post subject: Reply with quote

Thanks.
_________________
Back to top
View user's profile Send private message
Tuncay



Joined: 07 Nov 2006
Posts: 950

PostPosted: Mon Nov 09, 2009 10:53 pm    Post subject: Reply with quote

Small improvement in speed of GetParams():
Code:
cycles = 500000

; Original
x=0
start := a_tickcount
loop, %cycles%
{
If !RegExMatch( SubStr(%A_Index%, 1, 1), "(-|/)")
x++
}
end := a_tickcount - start
msgbox %end%:`n`n%x%

; Optimized
x=0
start := a_tickcount
loop, %cycles%
{
If !RegExMatch( SubStr(%A_Index%, 1, 1), "S)(?:-|/)")
x++
}
end := a_tickcount - start
msgbox %end%:`n`n%x%


The S) saves the regex in memory in binary form, for not process same regex again. It is a cache.

The ?: at begin of brace says not to save the result for later use.
Back to top
View user's profile Send private message
Yook



Joined: 20 Nov 2008
Posts: 64
Location: Thionville, France

PostPosted: Tue Nov 10, 2009 3:34 am    Post subject: Reply with quote

Thanx for the tip, Tuncay. It's the first time I use some RegEx functions in a script, used to use loads of SubStr() and InStr().
Back to top
View user's profile Send private message
Tuncay



Joined: 07 Nov 2006
Posts: 950

PostPosted: Tue Nov 10, 2009 4:09 am    Post subject: Reply with quote

Ah I wanted say more... forgot is simply, because I was in a rush. You dont need at that given example the SubStr() to extract first character. This could be done in the regex itself. If the regex (after options) start with character "^", the check is done from start of haystack.

Code:
RegExMatch(%A_Index%, "S)^[-/]")

should be enough.

The brackets "[" and "]" indicate a list of possible characters. There is no need for a delimiter. But I did not tested with your code. You can learn from this and apply to other functions. You can even create right from the regex the corresponding variables. All captured substrings between "(" and ")" are created to variables.
Back to top
View user's profile Send private message
Yook



Joined: 20 Nov 2008
Posts: 64
Location: Thionville, France

PostPosted: Thu Nov 12, 2009 1:21 am    Post subject: Reply with quote

Ok thanks, I rewrote some parts.
Back to top
View user's profile Send private message
wtg



Joined: 04 Oct 2006
Posts: 136
Location: Louisville, KY

PostPosted: Tue Apr 20, 2010 3:19 pm    Post subject: Reply with quote

Thanks for posting this. It works nicely and saved me a lot of brain power.

Yesterday I wanted to write a quick and dirty program that could parse a complex and changing command-line generated by another application and give me just the components I needed. Found this and had it working it about 5 minutes.

Thanks again!
Back to top
View user's profile Send private message
Yook



Joined: 20 Nov 2008
Posts: 64
Location: Thionville, France

PostPosted: Sat May 01, 2010 5:17 pm    Post subject: Reply with quote

You're welcome! glad I could help.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group