parsing of command-line style arguments

Posted by Victorious on Tue 28 Jun 2016 12:16 PM — 7 posts, 30,953 views.

#0
I want to have a command for a plugin that has the following form:
add <quantity> <spell name> [additional options] where additional options is a space-separated list of command-line style switches that may be specified.
For example, valid input would be "add 10 magic missile", or "add 10 magic missile -d someStringWhichMayHaveSpaces -s someOtherString". Is there a nice way of doing this using regex when the switches can come in any order, and may not even be present? Valid switches are -d, -p, -s, -v, -w.
Amended on Tue 28 Jun 2016 12:18 PM by Victorious
Australia Forum Administrator #1
What I would do here is use a simple wildcard, and then use Lua pattern-matching to parse the arguments.

For example: http://www.gammon.com.au/scripts/doc.php?lua=string.gmatch
#2
You suggest iterating over each word of the string?

Another idea i had was to have n regular expressions where n is the number of switches i support, something like "^.+ -d (.+)$" to pick out the argument for -d. The problem is that I need it to capture everything after -d, but stop just before encountering any of the other switches (e.g, "-w").
Australia Forum Administrator #3
This is what I am talking about:


<aliases>
  <alias
   match="^add (?P&lt;quantity&gt;\d*) *(?P&lt;spell&gt;[^-]+)(?P&lt;args&gt;.*)$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>

quantity = tonumber ("%&lt;quantity&gt;")
print ("quantity = ", quantity)
spell = Trim ("%&lt;spell&gt;")
print ("spell = ", spell)
args = "%&lt;args&gt;"
print ("args = ", args)

for arg, value in string.gmatch (args, "%-(%a)([^-]+)") do
  value = Trim (value)
  print ("Got argument", arg)
  print ("Got value", value)
end -- for

</send>
  </alias>
</aliases>


Template:pasting
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.


The regexp without all the XML around it (needed for pasting the whole alias) is:


^add (?P<quantity>\d*) *(?P<spell>[^-]+)(?P<args>.*)$


That is:

  • "add "
  • Zero or more digits, stored in capture "quantity"
  • Zero or more spaces after the digits (we already have a space after "add")
  • The spell name is anything except a hyphen - however at least one thing - stored in capture "spell"
  • The arguments are everything after the spell name (if anything), stored in capture "args"


The pattern for the arguments (in Lua regexp) is:

  • A hyphen
  • A letter
  • One or more of anything except a hyphen






Test string:


add 10 magic missile -d some String Which May Have Spaces -s someOtherString


Output:


quantity =  10
spell =  magic missile
args =  -d some String Which May Have Spaces -s someOtherString
Got argument d
Got value some String Which May Have Spaces
Got argument s
Got value someOtherString


Test:


add magic missile


Output:


quantity =  nil
spell =  magic missile
args =  


You can test for quantity == nil to see if quantity was supplied or not.
Amended on Thu 30 Jun 2016 05:55 AM by Nick Gammon
#4
Is it possible to allow for arguments to switches to contain the - character?
Australia Forum Administrator #5
Yes you can, but you have to rework it a bit:


<aliases>
  <alias
   match="^add (?P&lt;quantity&gt;\d*) *(?P&lt;spell&gt;[^-]+)(?P&lt;args&gt;.*)$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>

quantity = tonumber ("%&lt;quantity&gt;")
print ("quantity = ", quantity)
spell = Trim ("%&lt;spell&gt;")
print ("spell = ", spell)
args = "%&lt;args&gt;"
print ("args = ", args)

while true do
  -- find first argument
  st, en, arg = string.find (args, "%-(%a+)")

  -- see if any found
  if not st then
    break  -- all done!
  end -- if

  -- find next argument, if any
  st2 = string.find (args, " %-", en)
  if not st2 then
    st2 = -1
  end -- if not found

  value = Trim (args:sub (en + 1, st2))
  print ("Got argument", arg)
  print ("Got value", value)

  args = args:sub (st2)  -- remove this argument
end -- while


</send>
  </alias>
</aliases>


Template:pasting
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.


Test:


add 10 magic missile -d some String Which May Have Spaces -s some-Other-String -foo bar


Output:


quantity =  10
spell =  magic missile
args =  -d some String Which May Have Spaces -s some-Other-String -foo bar
Got argument d
Got value some String Which May Have Spaces
Got argument s
Got value some-Other-String
Got argument foo
Got value bar


I've made it this time so you can have a longer word (eg. "-foo") as the parameter name. Of course, then you have to have a space after it to delimit it from what the argument is.
#6
This looks perfect - thanks a lot :)