 |
|
 |
I tried the suggestion to remove |: from the Splitter regex and it does fix file name issue but now it can not read value of height defined as /height:'400' on the command line.
Also someone else suggested to make change in the regex. I can't find the original statement in the code, nor does the mod work.
Any help is much appreciated.
|
|
|
|
 |
|
 |
Very powerful and easy to use.
Never trust a computer you can't throw out a window.
|
|
|
|
 |
|
 |
Saved me hours of work and it works first go.
Have done this before many times in the old UNIX days
and didn't really want to go through it all again.
Thanks.
|
|
|
|
 |
|
 |
I am new to C# (old time C coder) and remember what a pain it was to parse args[]... this was a 10 minute setup (I had to figure out how to use "Project...Add existing item..." to add the .cs file to my project and w/o any code changes it just worked exactly how I needed it to.
Thanks!
|
|
|
|
 |
|
 |
This is a great little piece of code. Thumbs up for that.
It's also a beautiful illustration of the reputation of "the French way of doing things".
In the Netherlands we have a proverb about this.
I just hope people interested in this code have the time to go through all the comments, because without them, you might lose a lot of time debugging.
We also have a saying "Live like God in France", so it must be an enjoyable country to live in. Or at least at some point in time.
|
|
|
|
 |
|
 |
Thanks for the code. I intergrated it with an in-house project in 10 minutes.
I had to make the change to handle filename paths (Im need; -output c:\temp\foo.html, quickly fixed by removing |: from regex as posted below).
Nice one!
|
|
|
|
 |
|
 |
Thanks for the code example, GriffonRL. I used your class to quickly put together a parser for my program, defiantly less of a hassle then putting it together myself.
I'm not complaining, but just saying, because you look like your taking advice for the next version, the resulting calls to the object getting alittle messy with all the if else statements. Maybe it could be handled better on my end. It would also be cool to make the parser recognize two unique commands as being the same, like -h and -?, for example.
Anyway, thanks alot for the code, defiantly made my day easier, if I give any serious thought to improvements I'll post something more indepth.
|
|
|
|
 |
|
 |
The class seems to be broken when trying to use space separated name/value pairs. For example, a parameter such as:
-xmlFile="E:\HOME PWR Reports\MembershipRpt.xml"
returns a value of "true" for 'xmlFile'.
|
|
|
|
 |
|
 |
Hi,
Strange, the class is build to handle this kind of scenario. It works for me. You can try to use simple quotes instead of double quotes. Are you also passing other parameters before or after your xmlfile path ? I would like to reproduce the problem.
I may have also to try with the downloadable version on Codeproject because the version I casually use in my apps is an updated one.
Cheers,
R. LOPES
Just programmer.
|
|
|
|
 |
|
 |
Hi,
I didn't tried it yet but you can also tweak the splitter regex and remove the ':' character from it. The other reason could be the space you have in your path even if you enclosed everything inside double quotes. Of course, this should not be a problem unless... Unless you get the parameters from Environment.CommandLine instead of the Args array.
Happy coding,
R. LOPES
Just programmer.
|
|
|
|
 |
|
 |
Try this pls:
Regex isParam = new Regex(@"^^-{1,2}|^/",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
Regex Spliter = new Regex(@"^-{1,2}|^/|=|:",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
[...]
bool isparam = isParam.IsMatch(Txt);
if (isparam)
Parts = Spliter.Split(Txt, 3);
else
Parts = new string[] { Txt };
This will splitt only if - -- oder / detected.
|
|
|
|
 |
|
 |
I really like your command-line parser - alas, it lets me down in one case:
if I have an argument that expects a file name including a path, such as "C:\temp\*.xml", I cannot seem to get those properly.
When I call my app with an argument "/filespec c:\temp\*.xml", or even when I put the file name / path in double quotes ("), I always get "True" for the "filespec" argument.
It appears that the parser will choke on the ":" in the path and think this is another argument to split up; it should *NOT* do this, especially if the file path/file spec is enclosed in double quotes!
Any chance you could fix this? Also- whenever I download your code, I always seem to get the v1.0 version (Oct 2002) - not the bug fixed version of November. Did you upload the most current version at all?
Thanks again for a great little piece of software!
=============================
Marc Scheuner, Berne, Switzerland
mscheuner - at - gmail.com
May The Source Be With You!
|
|
|
|
 |
|
 |
Hi Marc,
Good points.
For your parsing problem, you found a problem. This could be fixed by tweaking the regex in case one use " or ' characters. The splitter regex has to be enhanced for such cases. But I may be not enough. I didn't have the time right now to look at the problem, because of a heavy schedule. If you are really in need you can give it a try.
That leads us to the second good point you made. I didn't updated the source in the past 2 years but I should do it some day because many people in the comments threads came up with good ideas and fixes. Again I am always postponing this task of puting every contributed bit together to upload an updated and rock solid version. However, I think I can manage at last a moment before mid-september to update the code, the article and give credits to every people who pointed out problems, fixes and enhancements. Please note I use an enhanced version of this class myself (but this doesn't include the fix you need).
I'm sorry not to come right now with a good answer. It's at the very least on my todo list.
Keep coding,
R. LOPES
Just programmer.
|
|
|
|
 |
|
 |
Simply removing the "|:" from the regex seems to fix the problem. That is never a legitimate delimiter that I have heard of anyway.
This also solves the problem above which has ":" in the parameter.
Dave
|
|
|
|
 |
|
 |
the "|:" delimiter is most certainly a valid delimiter, but only in one very specific instance is it ever used that I can think of. That instance being the processing of Optical Character Recognition fields when determining the begining of an ABA Routing numbers and Account numbers fields on checks. The "|:" is used to delimit the begining of a new field either the ABA Routing number or the account number example |:123456789|:1112223334444"' 0001 as you can see from this example the aba routing number is preceded and anteceded by the "|:" character and an OCR system is instructed that data to follow represents a contiguous field from that special delimiter. Hopefuly your needs will not include OCR Check Processing but if it does you may need to put that "|:" delimiter back in
HTH
|
|
|
|
 |
|
 |
that part of the regex does is not to allow "|:" as a delimiter, but is meant allow ":" as a delimiter between the parameter and the value.
in your example, leaving that bit in would cause the same problem with ABA routing numbers as it would for file paths, etc. But, only if you were passing in the Routing number as a value for a parameter.
|
|
|
|
 |
|
 |
I was able to fix this by:
First, changing the Remover so that it would match on quoted strings, instead of making the quotes optional: Regex Remover= new Regex(@"^['""](.*?)['""]$",RegexOptions.IgnoreCase|RegexOptions.Compiled);
Removing the ? following the character classes makes the classes required for a match. Now, you can differentiate between the quoted paramter value, and the parameter itself.
Then, before the switch change the single line that splits the Arg to
if (!Remover.IsMatch(Arg))
{
Parts = Splitter.Split(Arg, 3);
}
else
{
Parts = new String[] { Remover.Replace(Arg, "$1")};
}
Now, it will split the parameters correctly (since they will not start with a single, or double, quote.
And,if the parameters are separated by spaces, the value will have the quotes stripped before the switch.
|
|
|
|
 |
|
 |
He man, you've been doing a great job. I wrote a slightly different version of your code. The way i needed it was with 1 parameter who has got possible multiple values. In my case i wanted 1 parameter database, and then be able to write down multiple database-names. In my case there will be no true value if the parameter is standalone, it will have a value-colection with count == 0 this way i can put a line down like this: program.exe -database db1 db2 db2 -debug -build:1401 where db1, db2 and db3 will be added to the parameter database So here is what i did: using System; using System.Collections; using System.Collections.Specialized; using System.Text.RegularExpressions; namespace Piramide.Bis.Conversie.Util { /// <summary> /// CommandLine Argument Parser /// </summary> public class CmdArgParser { // Variables private Hashtable _parameters; public Hashtable Parameters { get { return _parameters; } } /// <summary> /// Constructor /// </summary> public CmdArgParser(string[] Args) { _parameters = new Hashtable(); Regex splitter = new Regex(@"^-|^/|=|:", RegexOptions.IgnoreCase|RegexOptions.Compiled); Regex remover = new Regex(@"^['""]?(.*?)['""]?$", RegexOptions.IgnoreCase|RegexOptions.Compiled); string parameter = null; string[] parts; ArrayList values = new ArrayList(); // Valid parameters: // {-,/}param{ ,=,:}((",')value(",')) // Examples: // -param1 value1 value2 -param2 /param3:"Test" /param4=happy foreach (string arg in Args) { parts = splitter.Split(arg,3); switch(parts.Length) { // Found value case 1: // if parameter still wait, add value to values-colection if(parameter != null) { parts[0] = remover.Replace(parts[0], "$1"); values.Add(parts[0]); } break; // found parameter case 2: // if paramater was still waiting, // then add parameter and values-collection to _parameters // clear values if(parameter!=null) { if(!_parameters.ContainsKey(parameter)) { _parameters.Add(parameter, values); values = new ArrayList(); } } parameter = parts[1]; break; // found parameter with enclosed value case 3: // if paramater was still waiting, // then add parameter and values-collection to _parameters // clear values if(parameter != null) { if(!_parameters.ContainsKey(parameter)) { _parameters.Add(parameter, values); values = new ArrayList(); } } // Parameter with enclosed value is allowed only one value. // add parameter and value to _parameters parameter = parts[1]; parts[2] = remover.Replace(parts[2], "$1"); values.Add(parts[2]); if(!_parameters.ContainsKey(parameter)) _parameters.Add(parameter, values); parameter=null; values = new ArrayList(); break; } } // if final parameter is still waiting, // add parameter and values to _parameters if(parameter != null) { if(!_parameters.ContainsKey(parameter)) _parameters.Add(parameter, values); } } // Retrieve a parameter value-collection if it exists // (overriding C# indexer property) public ArrayList this [string Param] { get { return (ArrayList)(_parameters[Param]); } } } } Raymond Molenaar r.molenaar@piramide.nl
|
|
|
|
 |
|
 |
Hi,
Thanks.
This is also a good variation on the subject.
One clear goal when designing such simple class is that everyone can easily get into the code and adapt it quickly to its very own requirements.
Thanks for sharing,
R. LOPES
Just programmer.
|
|
|
|
 |
|
 |
any idea on how to rewrite this for c++? i am really having trouble converting it at one place
// Retrieve a parameter value if it exists
public string this [string Param]{
get{
return(Parameters[Param]);
}
}
|
|
|
|
 |
|
 |
Hi,
Sorry to answer so late.
As far as I know you can't do this kind of "operator" overloading in C++.
I may be wrong because I didn't wrote a single line of C++ code in the past 4 years, and I know you can overload almost evrything, but this case is special.
Sorry,
R. LOPES
Just programmer.
|
|
|
|
 |
|
 |
porting to C++/CLI went quite straight-forward.
For the index access I used the so-called 'default indexed property':
public ref class Arguments
{
Collections::Specialized::StringDictionary^ parameters;
public:
Arguments(array ^args);
property String^ default [String^]
{
String^ get(String^ key)
{
return parameters[key];
}
}
};
You use it in the same way as in C#:
int main(array ^args)
{
...
Arguments^ arguments = gcnew Arguments(args);
if (arguments["help"])
Console::Write(helpMessage);
...
}
The complete class can be downloaded from here
|
|
|
|
 |
|
 |
If the application name has quotes around it and there is a string argument with quotes, the Regex in Parser.ExtractApplicationName does a greedy match. The Regex needs to be changed from
Regex r = new Regex(@"^(?("".+""|(\S)+))(?.+)",
RegexOptions.ExplicitCapture);
to
Regex r = new Regex(@"^(?(""[^""]+""|(\S)+))(?.+)",
RegexOptions.ExplicitCapture);
|
|
|
|
 |
|
 |
Hi Chris,
Thanks fo sharing,
R. LOPES
Just programmer.
|
|
|
|
 |
|
 |
Just wanted to add my thanks, like some others this class didn't support the exact syntax of arguments I wanted but it only took a few mins to update it and as skeleton for custom argument requirements I highly recommend it.
|
|
|
|
 |