Class For Parsing Windows Command Line

This is more of a snippet for myself. This is useful for parsing command lines for Windows Console applications and I have written code like this many times over. This class parses command lines of the form:

someprogram.exe /<switch0>:<switch0 value> /<switch1> /<switch2>:<switch2 value enclosed in quotes>

An example would be:

foo.exe /source:"C:\temp\path with spaces" /source:C:\temp\foo /dest:C:\DestFolder /c /o

Note the duplicate entry for /source. This class supports the same switch appearing multiple times.

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace ConParse
{
    /// <summary>
    /// This class will parse a Windows console application command line.
    /// <remarks>
    /// Switches are entered in the form 
    /// Example: YourProgram.exe /switchname:&quot;switch value with spaces in quotes&quot; /f /sec:90  /src:C:\temp /src:"C:\temp\foo dir"
    /// Switches start with / followed by a single character or string token for the switch.  Switches with values are followed by a colon :.
    /// Values with spaces in them are enclosed in quotes.  A particulare switch may be entered more than once.
    /// </remarks>
    /// </summary>
    public class CArgs : Dictionary<string, List<string>>
    {
        /* Without excaped quotes, the Regex looks like the following below.
(?<=/) (?<sw>\w+) 
(?<co>:)?   (?(co) (?<qu>")?    
                (?(qu) (?<arg> [^"]+)" | (?<arg> \S+)  )
            ) 
         */

        // pattern to parse the command line
        private const string _PATTERN = @"(?<=/) (?<sw>\w+) 
(?<co>:)?   (?(co) (?<qu>"")?    
                (?(qu) (?<arg> [^""]+)"" | (?<arg> \S+)  )
            )  ";

        /// <summary>
        /// Constructor, parses the command line and populates the dictionary.
        /// </summary>
        public CArgs()
        {

            // get complete command line
            string sCmdLine = Environment.CommandLine;

            // sanity check, should never be true
            if (string.IsNullOrEmpty(sCmdLine))
                return;

            // we get the name of the program at the beginning of the command line.  This we want to strip out
            string[] args = Environment.GetCommandLineArgs();

            // sanity check, these should never be true
            if (null == args)
                return;

            // other sanity check, should not be true
            if (args.Length < 1)
                return;

            // first arg is the path to the program
            string arg0 = args[0];
            if (!string.IsNullOrEmpty(arg0))
            {
                int startAt = arg0.Length;

                // the command line may being with a quote for an exe in a path with spaces, args[0] will no have the quotes
                if (sCmdLine.StartsWith("\""))
                    startAt += 2;

                // strip out the exe part
                sCmdLine = sCmdLine.Substring(startAt);
            }

            // parse the command line switches
            Match mt = Regex.Match(sCmdLine, _PATTERN, RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);
            string sw = null;
            string sarg = null;
            List<string> vals = null;
            while (mt.Success)
            {
                sw = mt.Groups["sw"].Value;
                sarg = mt.Groups["arg"].Value;

                if (this.ContainsKey(sw))
                {
                    vals = this[sw];
                }
                else
                {
                    vals = new List<string>();
                    this[sw] = vals;
                }

                //switches without values will have empty string values.
                vals.Add(sarg ?? string.Empty);

                mt = mt.NextMatch();
            }
        }
    }
}

Download PDF
This entry was posted in C#, Code Samples and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *