正则表达式来解析命令行

时间:2012-11-04 16:11:48

标签: c# regex

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

  

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

3 个答案:

答案 0 :(得分:1)

如果您使用的是标准的控制台应用程序,那么主入口点args []已经为您解析了这个问题。这里有一个警告,因为你提供的例子因为它们中的空格(C:\ Program Files)而无法工作,但如果你用引号括起它们(“C:\ Program Files \ Internet ... \ iexplorer”) .exe“)你会发现这个工作正常。

link walks you through creating a console application

<强>更新

那么,如果它不是控制台应用程序,但您想要模拟控制台应用程序启动例程为您提供的确切内容,我可以向您介绍唯一的 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);
        }
    }
}

答案 1 :(得分:1)

根据您的问题,我假设您正在寻找一种在Windows操作系统上以文本形式传递批处理命令的方法。我能想到你成功做到这一点的唯一方法是,如果你有一个所有命令的列表,或者如果你的程序可以提取系统中的所有.exe文件,那么你可以成功检查第一个exe文件的位置< em>这是命令的目标程序,并将其他程序视为参数。

这样,你可以像这样进行提取(非正则表达式方法):

var cmd = "copy this.txt C:\t.txt"
var program = getTargetProgram(cmd);
var args = cmd.Substring(cmd.IndexOf(program) + program.length).trim().split(' ');

你的getTargetProgram()可能是这样的:

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
       }
    }
}

答案 2 :(得分:0)

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

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

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