|
awesome...this is what i was looking for...i had a quick question though...in you reg expression...
@"^([/-]|--){1}(?<name>\w+)([:=])?(?<value>.+)?$"
I was trying to get it where it would accept -flag"value". I have...
@"^([/-]|--){1}(?<name>\w+)([:\x22])?(?<value>.+)?$"
but it matches the tag as flagvalue. If I use any other character like the = or a single quote then it works.
I am not very good with regex yet so any help is appreciated. (I did try for a while before posting).
|
|
|
|
|
never mind! turns out the .net command line parser strips the quotes before it even gets to it.
|
|
|
|
|
its not the regex' problem. the problem is that -test"ddd" on the commandline becomes args[0] -> -testddd, so its .NETs fault (its being nice and removed "" for you because it thinks its a path).
A workaround is to get the full commandline via Environment.CommandLine, but then you have to parse and split the commandline manually yourself before handing it over the the regex parser. Or you could just use -test:"ddd"
Edit:
doh! i saw just now that you figured it you yourself
|
|
|
|
|
very useful!
works like a dream, i appreciate the time and effort -
saved me a bit of time and thinking
¡gracias con mucho gusto!
t hughes
|
|
|
|
|
Thank you so much.
Look inside the messages for an enhanced version submitted by a user.
Cheers,
R. LOPES
Just programmer.
|
|
|
|
|
I have used this and adapted it for use in my app. I am writing a small GUI and I need to grab those paramaters from the command line.... I have used everything including myValue=params["param1"];
As of now, the arguments I pass with the command are written to the console. I am just brain dead on how to seperate and assign the values of these parameters, so that I can populate global variables and text boxes with the values..
Any help would be MUCH appreciated.
Thanks, another programmer with too much work and not enough qualifications...
|
|
|
|
|
Hi,
Thanks for your interest. Please note that the latest source is in fact in one of the messages below. I still didn't updated the article code.
From what I understand from your problem it doesn't sound too difficult, but maybe I didn't catch every subtilities here.
Could you please post your code or send me your form with an explanation on what you want to achieve. Just send me the minimum.
Cheers,
R. LOPES
Just programmer.
|
|
|
|
|
The app I am writing basically combines several command line parameters and user input into a concat string which is sent as a request through an IP socket. I have most of everything else working, the socket, message etc. I have included some bits of my code below, as I am getting desperate. I need to take the command line parameters and assign them to strings that I declare in the beginning. I need these command line parameters to not only populate a few text boxes, but assign them to variables which are concatenated with other variables based on user input into one single string later on. Basicaly, I am woefully underqualified, and I do not know or underttand how or where or what syntax to take commandline parameter 1 which is called localIP and assign it to this.localIP so I can use it to populate a text box, and use in a new concatenated string. I just need to know what to type and where for each parameter.
I incorporated the code arguments.cs and test.cs and it works... It will list the command line params or tell me they were not defined! I am fine with that, I ust need to grab the values and have no clue.
Thanks!
[STAThread]
static void Main(string[] args)
{
Application.Run(new Form1());
// Command line parsing
Arguments CommandLine=new Arguments(args);
// Look for specific arguments values and display
// them if they exist (return null if they don't)
if(CommandLine["localIP"] != null)
Console.WriteLine("localIP value: " +
CommandLine["localIP"]);
else
Console.WriteLine("Local IP Address not defined !");
if(CommandLine["iMUSEnum"] != null)
Console.WriteLine("iMUSEnum value: " +
CommandLine["iMUSEnum"]);
else
Console.WriteLine("iMUSE Terminal Number not defined !");
if(CommandLine["appFunction"] != null)
Console.WriteLine("appFunction value: " +
CommandLine["appFunction"]);
else
Console.WriteLine("Application Function not defined !");
if(CommandLine["ICAO"] != null)
Console.WriteLine("ICAO value: " +
CommandLine["ICAO"]);
else
Console.WriteLine("ICAO not defined !");
if(CommandLine["checkType"] != null)
Console.WriteLine("checkType value: " +
CommandLine["checkType"]);
else
Console.WriteLine("Check-In Type not defined !");
if(CommandLine["vuelo"] != null)
Console.WriteLine("vuelo value: " +
CommandLine["vuelo"]);
else
Console.WriteLine("Vuelo not defined !");
if(CommandLine["schedTime"] != null)
Console.WriteLine("schedTime value: " +
CommandLine["schedTime"]);
else
Console.WriteLine("Scheduled Flight Time not defined !");
if(CommandLine["destIP"] != null)
Console.WriteLine("destIP value: " +
CommandLine["destIP"]);
else
Console.WriteLine("Destination IP Address not defined !");
if(CommandLine["destPort"] != null)
Console.WriteLine("destPort value: " +
CommandLine["destPort"]);
else
Console.WriteLine("Destination Port not defined !");
}
#endregion
private void param()
{
// MyValue=params["MyParam"]
//Assign Command Line Args To Variables
this.localIP = "";
this.iMUSEnum = "";
this.appFunction = "";
this.terminal = "";
this.ICAO = "";
this.checkType = "";
this.vuelo = "";
this.schedTime = "";
this.destIP = "";
this.destPort = "";
//Assign Variables To Diagnostic Text Boxes
Diagtxt1.Text = this.localIP;
Diagtxt2.Text = this.iMUSEnum;
Diagtxt3.Text = this.appFunction;
Diagtxt4.Text = this.terminal;
Diagtxt5.Text = this.ICAO;
Diagtxt6.Text = this.checkType;
Diagtxt7.Text = this.vuelo;
Diagtxt8.Text = this.schedTime;
Diagtxt10.Text = this.destIP;
Diagtxt11.Text = this.destPort;
Diagcmb1.Text = this.action;
}
// Creates The Request
public void createRequest()
{
// Message For Check-In Open In Simulataneous Mode
if (this.appFunction == "1" && this.action == "01" && this.checkType == "S")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, ICAO);
this.Diagtxt12.Text = message;
}
// Message For Check-In Open In Differentiated Mode
if (this.appFunction == "1" && this.action == "01" && this.checkType == "D")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, vuelo, schedTime);
this.Diagtxt12.Text = message;
}
// Message For Sending Complimentary Text
if (this.appFunction == "1" && this.action == "02")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, space, compText);
this.Diagtxt12.Text = message;
}
// Message For Sending Manual Text
if (this.appFunction == "1" && this.action == "06")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, freeText);
this.Diagtxt12.Text = message;
}
// Message For Close In Simultaneous Mode
if (this.appFunction == "1" && this.action == "06" && this.checkType == "S")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, ICAO);
this.Diagtxt12.Text = message;
}
// Message For Close In Differentiated Mode
if (this.appFunction == "1" && this.action == "06" && this.checkType == "D")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, vuelo, schedTime);
this.Diagtxt12.Text = message;
}
// Message For Boarding Gate Open
if (this.appFunction == "2" && this.action == "09")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, ICAO);
this.Diagtxt12.Text = message;
}
// Message For Final Boarding Call
if (this.appFunction == "2" && this.action == "07")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, ICAO);
this.Diagtxt12.Text = message;
}
// Message For Boarding Gate Close
if (this.appFunction == "2" && this.action == "06")
{
string message = string.Concat(localIP, space, iMUSEnum, appFunction, terminal, space, setVal, ICAO, setVal2, action, checkType, vuelo, schedTime);
this.Diagtxt12.Text = message;
}
string request = this.Diagtxt12.Text;
this.IPrequest = request;
}
|
|
|
|
|
Hi,
My guess is that you are parsing the command line at the wrong place in your code.
At least you should start by parsing the command line and then call:
Application.Run(new Form1());
You currently do the opposite. Application.Run(...) being a blocking call, that returns only when you close your Form1, the parsing code is only executed just before ending the application, which seems useless.
Another idea if you then want to initialize your form controls with command line arguments, is to pass the command line to the form and parse it from there.
Create another construtor, something like:
public Form1(string[] args){<br />
Arguments CommandLine=new Arguments(args);<br />
...<br />
}
And then change your Main function to Application.run(new Form1(args));
Please note that there is another way to get the command line arguments. Anywhere in your code, including in the parameterless Form1 constructor, you can write this:
Arguments CommandLine=new Arguments(Environment.CommandLine);
.NET automatically copy the command line to the Environment.CommandLine property when the application is started.
As soon as you have parsed your arguments, you can then type this.localIP=CommandLine["localIP"] and set a textbox value like this.localIPTextBox.Text=CommandLine["localIP"].ToString(); (do this after InitializeComponent() in your form)
Hope this helps,
R. LOPES
Just programmer.
|
|
|
|
|
Your light-weight, effecive, easy-to-understand code was just what I was looking for. Your well-documented example made it easy to plug-in to my code too. Thanks for sharing this. Unlike some other solutions, this graciously handles quoted values, too.
I'd recommend this to anyone who wants a quick pre-fabricated solution to handling command-line parameters.
You get my 5.
Très bien et merci!
|
|
|
|
|
Hi Christopher,
Thank you for your interest in this very simple piece of code (yet effective !), and your kind words.
Merci,
R. LOPES
Just programmer.
|
|
|
|
|
I like this parser a lot since it is simple but still powerful. However, it lackes one feature.
If I make a file association, so the application automatically is launched when the user double-clicks on a data-file, the data-filename will be sent to the application as a command line argument. This argument does not start with '-' or '/' but I still would like the parser to store it for me. I have therefore expanded the class to also support "unnamed" arguments and can retrieve them by their index value.
/// <summary>
/// Command line parser.
/// </summary>
/// <remarks>
/// Create an object from this class with the command line array
/// from the <c>Main</c> method. It will automatically parse the
/// command line arguments, find all parameters starting with -, -- or
/// / and all the values linked. Any value could be separated from the
/// parameter with a space, a : or a =. The parser also look for
/// enclosing characters like ' or " and remove them. Of course if you
/// have a value like 'Mike's house', only the first and last ' will be
/// removed.
/// </remarks>
/// <example>
/// Here is an example on how to retrieve the command line arguments.
/// <code>
/// static void Main(string[] Args)
/// {
/// CommandLineArguments cml = new CommandLineArguments(Args);
///
/// if (cml["Height"]!=null)
/// Console.WriteLine( "Height: "+CommandLine["Height"] );
/// else
/// Console.WriteLine( "Height is not defined !" );
///
/// if (cml["Width"]!=null)
/// Console.WriteLine( "Width: "+CommandLine["Width"] );
/// else
/// Console.WriteLine( "Width is not defined !" );
/// }
/// </code>
/// If a file extension has been associated with the program, and
/// the user double-clicks on the file, the filename will be added
/// as a command line argument by Windows. This is an unnamed argument
/// and must therefore be retrieved by its index value (of unnamed
/// arguments):
/// <code>
/// static void Main(string[] Args)
/// {
/// CommandLineArguments cml = new CommandLineArguments(Args);
///
/// if (cml[0]!=null)
/// Console.WriteLine( "Open file: " +CommandLine[0] );
/// else
/// Console.WriteLine( "No file to open..." );
/// }
/// </code>
/// </example>
public class CommandLineArguments
{
private StringDictionary namedParameters =
new StringDictionary();
private System.Collections.ArrayList unnamedParameters =
new System.Collections.ArrayList();
/// <summary>
/// Creates a <see cref="CommandLineArguments"/> object to parse
/// command lines.
/// </summary>
/// <param name="args">The command line to parse.</param>
public CommandLineArguments(string[] args)
{
Regex splitter = new Regex(@"^-{1,2}|^/|=|:",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
Regex remover = new Regex(@"^['""]?(.*?)['""]?$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
string parameter = null;
string[] parts;
// Valid parameters forms:
// {-,/,--}param{ ,=,:}((",')value(",'))
// Examples: -param1 value1 --param2 /param3:"Test-:-work"
// /param4=happy -param5 '--=nice=--'
foreach (string str in args)
{
// Do we have a parameter (starting with -, /, or --)?
if (str.StartsWith("-") || str.StartsWith("/"))
{
// Look for new parameters (-,/ or --) and a possible
// enclosed value (=,
parts = splitter.Split(str, 3);
switch (parts.Length)
{
// Found a value (for the last parameter found
// (space separator))
case 1:
if (parameter != null)
{
if (!namedParameters.ContainsKey(parameter))
{
parts[0] =
remover.Replace(parts[0], "$1");
namedParameters.Add(
parameter, parts[0]);
}
parameter = null;
}
// else Error: no parameter waiting for a value
// (skipped)
break;
// Found just a parameter
case 2:
// The last parameter is still waiting. With no
// value, set it to true.
if (parameter != null)
{
if (!namedParameters.ContainsKey(parameter))
namedParameters.Add(parameter, "true");
}
parameter = parts[1];
break;
// parameter with enclosed value
case 3:
// The last parameter is still waiting. With no
// value, set it to true.
if (parameter != null)
{
if (!namedParameters.ContainsKey(parameter))
namedParameters.Add(parameter, "true");
}
parameter = parts[1];
// Remove possible enclosing characters (",')
if (!namedParameters.ContainsKey(parameter))
{
parts[2] = remover.Replace(parts[2], "$1");
namedParameters.Add(parameter, parts[2]);
}
parameter = null;
break;
}
}
else
{
unnamedParameters.Add(str);
}
}
// In case a parameter is still waiting
if (parameter != null)
{
if (!namedParameters.ContainsKey(parameter))
namedParameters.Add(parameter, "true");
}
}
/// <summary>
/// Retrieves the parameter with the specified name.
/// </summary>
/// <param name="name">
/// The name of the parameter. The name is case insensitive.
/// </param>
/// <returns>
/// The parameter or <c>null</c> if it can not be found.
/// </returns>
public string this[string name]
{
get { return (namedParameters[name]); }
}
/// <summary>
/// Retrieves an unnamed parameter (that did not start with '-'
/// or '/').
/// </summary>
/// <param name="name">The index of the unnamed parameter.</param>
/// <returns>The unnamed parameter or <c>null</c> if it does not
/// exist.</returns>
/// <remarks>
/// Primarily used to retrieve filenames which extension has been
/// associated to the application.
/// </remarks>
public string this[int index]
{
get
{
return (string)(index < unnamedParameters.Count ?
unnamedParameters[index] :
null);
}
}
}
|
|
|
|
|
Hi,
Thank you.
And again a great addition !
I didn't tested your code yet, but I will, since I use this simple class every time I need it.
I also want to take this occasion to tell everyone again that the source code is free for your use and may be modified to fit all your needs. Build everything you want based on this, commercial or not.
I'm just happy to see people using this code and enjoying it.
I should consider update the article to include all the additions made by all the contributors in the past 2-3 years, and offer an up to date source code to download.
Have a great day,
R. LOPES
Just programmer.
|
|
|
|
|
Please do, I really like your parser! / Anders Bjerin
|
|
|
|
|
Please, please, please, that would be a great idea to update the orignal article. Great class and thanks!
|
|
|
|
|
That would be great! Please do
-Matthias
|
|
|
|
|
Hi Anders Bjerin,
I liked the idea of your modification, but it didn't acutally work for me. The problem was that all space delimited parameters were getting a value of "true" while the specified values were being placed as unnamed parameters.
For instance:
myapp -f filename -x
The named parameters and values were:
"f" - "true"
"x" - "true"
And the unnamed parameters were:
"filename"
I fixed it in my application by replacing this line:
if (str.StartsWith("-") || str.StartsWith("/"))
With this:
if (str.StartsWith("-") || str.StartsWith("/") || parameter != null)
In the foreach loop, the space delimited values of a parameter will not start with "-" or "/". When a parameter is found the "parameter" variable is set. When that parameter is assigned a value, the "parameter" variable is reset to null. So if (parameter!=null) we still need to check for the following string.
The code already handles "valueless" parameters that are followed by additional parameters or are the last parameter, so no more modifications are needed.
This should fix the issues with your modified code and space delimited parameters.
Hope this makes sense,
pb
|
|
|
|
|
for example my.exe /help and my.exe /Help, then call your
Argument clArgs = new Argument(args);
alArgs["Help"] and alArgs["help"] will return samething or differently?
WWW: http://hardywang.1accesshost.com
ICQ: 3359839
yours Hardy
|
|
|
|
|
The StringDictionary handles keys in a case-insensitive manner. The keys are automatically translated to lower case before they are used with the StringDictionary.
|
|
|
|
|
It is not case sensitive as presented here. To make it case sensitive (which is more useful, I think):
1. Change the line "private StringDictionary Parameters;" to "private System.Collections.Hashtable Parameters;"
2. Change the line "Parameters=new StringDictionary();" to "Parameters = new System.Collections.Hashtable();"
3. Remove the "RegexOptions.IgnoreCase" option from both Regex constructor calls.
4. Change the line "return(Parameters[Param]);" to "return((string)Parameters[Param]);"
|
|
|
|
|
Richard,
I have written an application framework called Razor, in which I have based a command line parser upon code I found here on the Code Project several years ago. I believe strongly that it was your code that formed the basis for my parser. It has been a long time since I originally discovered your code and liked your approach. During the course of developing the parser I included in my code, I couldn't remember where I found the code that gave me the ideas.
At anyrate, I was wondering if you would consider allowing me to continue to distribute the parser in my framework. I believe I have changed things, but I would like very much to give you full credit for the regular expressions and other logic. I would also very much like to include notes that give you credit for the original work. You can find the first article on Razor posted on the code project under my articles. Check it out if you would like! I think you will see I have put it to good use!
Thanks for your work, it's helped me out greatly!
- Mark
Si vic pacem para bellum - If you want peace, prepare for war
|
|
|
|
|
Hi,
Thank you.
It has been a long time since you wrote this nice message.
I have been very busy in the past year and still look at CodeProject every single day, but I didn't found the time to contribute again.
I just want to take this occasion to tell everyone that the source code is free for your use and may be modified to fit all your needs. Build everything you want based on this, commercial or not.
Have a great day,
R. LOPES
Just programmer.
|
|
|
|
|
Can I include this class in GPL'd code? Of course, your name shall be mentioned.
Regards,
Alvaro Ramirez
|
|
|
|
|
Hi,
I know your question is maybe out of date, but just to let everyone else know that this code is not even GPL'ed. It is more than that. It's totally free for your use and may be modified to fit all your needs. Build everything you want based on this, commercial or not.
Have a great day,
R. LOPES
Just programmer.
|
|
|
|
|
I wrote a VB version of it, straight from the 'Why not something simpler' thread. It seems to work perfectly.
<br />
'<br />
' Arguments class: application arguments interpreter<br />
'<br />
' Authors: R. Lopes<br />
' Contributors: Hastarin, E. Marcon (VB version)<br />
' Created: 25 October 2002<br />
'<br />
' Version: 1.0<br />
'/<br />
<br />
Imports System<br />
Imports System.Collections.Specialized<br />
Imports System.Text.RegularExpressions<br />
<br />
Namespace CommandLine.Utility<br />
<br />
Public Class Arguments<br />
Inherits StringDictionary<br />
<br />
Dim lastName As String = Nothing<br />
Dim trimChars As Char() = {"""", "'"}<br />
Public nameValueRegex As New Regex("^([/-]|--){1}(?<name>\w+)([:=])?(?<value>.+)?$", RegexOptions.Compiled)<br />
<br />
Sub New(ByVal args As String())<br />
' Constructor<br />
' Valid parameters forms: <br />
' {-,/,--}param{ ,=,:}((",')value(",')) <br />
' Examples: -param1 value1 --param2 /param3:"Test-:-work" /param4=happy -param5 '--=nice=--' <br />
Dim arg As String<br />
Dim match As Match<br />
For Each arg In args<br />
match = nameValueRegex.Match(arg)<br />
If match.Success Then<br />
lastName = match.Groups("name").Value<br />
Add(lastName, match.Groups("value").Value.Trim(trimChars))<br />
Else<br />
' Found a value (for the last parameter found (space separator)) <br />
If Not (lastName Is Nothing) Then<br />
' Matched a name, optionally with inline value <br />
Me.Item(lastName) = arg.Trim(trimChars)<br />
End If<br />
End If<br />
Next arg<br />
End Sub<br />
<br />
End Class<br />
End Namespace<br />
|
|
|
|
|