Reputation: 331
I need a Regular Expression to parse commands such as:
C:\Program Files\Internet Explorer\iexplore.exe https:\www.google.com
C:\Program Files\Internet Explorer\iexplore.exe http:\www.google.com
C:\Program Files\Internet Explorer\iexplore.exe www.google.com
iexplore.exe https:\www.google.com
copy C:\test.txt D:\
The point is that I want to get the first part as command and the other parts as arguments. Commands can be anything including .bat
, .vbs
, .exe
etc.
Found a Regular Expression which is working normally if there is no space in command.
string str = @"C:\xcopy D:\test.txt D:\Test";
string pattern = @"^(?:""([^""]*)""\s*|([^""\s]+)\s*)+";
Regex parseDir = new Regex(pattern, RegexOptions.IgnoreCase);
if(parseDir.IsMatch(str))
{
Match dir = parseDir.Match(str);
var captures = dir.Groups[1].Captures.Cast<Capture>().Concat(
dir.Groups[2].Captures.Cast<Capture>()).
OrderBy(x => x.Index).
ToArray();
string cmd = captures[0].Value;
string arguments = string.Empty;
for (int i = 1; i < captures.Length; i++)
{
arguments += captures[i].Value + " ";
}
Console.WriteLine(cmd);
Console.WriteLine(arguments);
}
Upvotes: 2
Views: 2194
Reputation: 18023
If you're using a standard Console application, the main entry point args[] will already have parsed this for you. There's a caveat here, because the examples you've provided won't work because of the spaces in them (C:\Program Files) but if you surround them with quotes ("C:\Program Files\Internet ...\iexplorer.exe") you'll find this works correctly.
This link walks you through creating a console application
UPDATE:
Well then, if it's not a console application but you'd like to simulate exactly what the Console Application start-up routine provides you, may I introduce to you the one and only CommandLineToArgvW native method.
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine,
out int pNumArgs);
This ridiculously simple method takes any string and converts it into an array. Here's a utility class that you can use to convert your text input into a well formed array.
/// <summary>
/// Wrapper class for Win32 API calls
/// </summary>
public class NativeMethods
{
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);
/// <summary>
/// Parse a string into an array, including items in quotes
/// </summary>
/// <param name="commandLine"></param>
/// <returns></returns>
public static string[] CommandLineToArgs(string commandLine)
{
if (String.IsNullOrEmpty(commandLine))
return new string[] {};
int argc;
var argv = CommandLineToArgvW(commandLine, out argc);
if (argv == IntPtr.Zero)
throw new System.ComponentModel.Win32Exception();
try
{
var args = new string[argc];
for (var i = 0; i < args.Length; i++)
{
var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
args[i] = Marshal.PtrToStringUni(p);
}
return args;
}
finally
{
Marshal.FreeHGlobal(argv);
}
}
}
Upvotes: 1
Reputation: 445
You either need to put quotes around the program path/name (if it has spaces in it), or write some extra code to figure out the program part of it.
One approach that comes to mind is to start with the first capture (for your iexplorer.exe
example, it would be C:\Program
), check if it's a valid program. If not, add the next capture with a space (e.g., C:\Program
+ Files\Internet
=> C:\Program Files\Internet
) and repeat the check. Repeat until you've run out of captures or have found a valid program, and treat the rest as arguments normally.
No reason to do the parsing manually, as another answer suggested. The regexes will still work.
Upvotes: 0
Reputation: 10054
From your question, I'm assuming you are looking for a way to pass batch commands in a text on the Windows OS. The only way I can think of for you to do this successfully is if you have a list of all the commands or if your program can extract all the .exe files in the system, that way you can successfully check where the first exe file which is the target program of the command is and assume the others as arguments.
This way, you can do your extraction like this (Non-regex method):
var cmd = "copy this.txt C:\t.txt"
var program = getTargetProgram(cmd);
var args = cmd.Substring(cmd.IndexOf(program) + program.length).trim().split(' ');
your getTargetProgram()
could go like this:
private string getTargetProgram(string cmd)
{
//first test if it's a normal executable
if(File.Exists(cmd.Substring(0, cmd.IndexOf(".exe") + 4)) //return this extract;
foreach(string s in winProgramList)
{
if(cmd.StartsWith(s)){
//voila, we can return the target
}
}
}
Upvotes: 1