AutoHotkey Community

It is currently May 26th, 2012, 11:49 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: November 8th, 2009, 5:12 pm 
Offline

Joined: November 20th, 2008, 6:00 pm
Posts: 72
Location: Thionville, France
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 May 1st, 2010, 5:32 pm, edited 6 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 9th, 2009, 10:08 am 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Thanks.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 9th, 2009, 10:53 pm 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1934
Location: Germany
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 10th, 2009, 3:34 am 
Offline

Joined: November 20th, 2008, 6:00 pm
Posts: 72
Location: Thionville, France
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().


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 10th, 2009, 4:09 am 
Offline

Joined: November 7th, 2006, 9:47 pm
Posts: 1934
Location: Germany
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 12th, 2009, 1:21 am 
Offline

Joined: November 20th, 2008, 6:00 pm
Posts: 72
Location: Thionville, France
Ok thanks, I rewrote some parts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 20th, 2010, 3:19 pm 
Offline

Joined: October 4th, 2006, 2:15 am
Posts: 250
Location: Louisville, KY
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!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 1st, 2010, 5:17 pm 
Offline

Joined: November 20th, 2008, 6:00 pm
Posts: 72
Location: Thionville, France
You're welcome! glad I could help.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: Apollo, iDrug, Miguel and 58 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group