2

我需要一个正则表达式来解析命令,例如:

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
复制 C:\test.txt D:\

关键是我想将第一部分作为命令,将其他部分作为参数。命令可以是任何东西,包括,.bat等。.vbs.exe

如果命令中没有空格,则找到一个正常工作的正则表达式。

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);
}
4

3 回答 3

1

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
       }
    }
}
于 2012-11-04T16:29:44.330 回答
1

如果您使用的是标准控制台应用程序,则主入口点 args[] 已经为您解析了这个。这里有一个警告,因为您提供的示例由于其中的空格 (C:\Program Files) 而不起作用,但是如果您用引号将它们括起来 ("C:\Program Files\Internet ...\iexplorer .exe") 你会发现它可以正常工作。

链接将引导您完成创建控制台应用程序

更新:

那么,如果它不是控制台应用程序,但您想准确模拟控制台应用程序启动例程为您提供的功能,我可以向您介绍唯一的CommandLineToArgvW本机方法。

    [DllImport("shell32.dll", SetLastError = true)]
    static extern IntPtr CommandLineToArgvW(
        [MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, 
        out int pNumArgs);

这个非常简单的方法接受任何字符串并将其转换为数组。这是一个实用程序类,可用于将文本输入转换为格式良好的数组。

    /// <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);
        }
    }
}
于 2012-11-04T16:19:06.783 回答
0

您要么需要在程序路径/名称周围加上引号(如果其中有空格),要么编写一些额外的代码来找出它的程序部分。

想到的一种方法是从第一个捕获开始(对于您的iexplorer.exe示例,它将是C:\Program),检查它是否是有效的程序。如果不是,请使用空格添加下一个捕获(例如,C:\Program+ Files\Internet=> C:\Program Files\Internet)并重复检查。重复直到你用完捕获或找到一个有效的程序,然后将其余的正常视为参数。

正如另一个答案所建议的那样,没有理由手动进行解析。正则表达式仍然有效。

于 2012-11-04T17:00:38.093 回答