2013-06-11 78 views
4

我想分割一个字符串使用空格作为我的分隔符,但如果有多个单引号括起来的单词,那么我希望他们返回作为一个项目。正则表达式函数解析一个命令行,而不使用库

例如,如果输入字符串是:

CALL "C:\My File Name With Space" /P1 P1Value /P1 P2Value

输出数组是:

Array[0]=Call 
Array[1]=C:\My File Name With Space 
Array[2]=/P1 
Array[3]=P1Value 
Array[4]=/P1 
Array[5]=P2Value 

如何使用正则表达式来做到这一点?我意识到有命令行解析器。我粗略地看了一下流行的一个,但它没有处理可以有多个具有相同名称的参数的情况。无论如何,不​​要学习如何使用命令行解析库(在另一天留下它)。我有兴趣更多地接触RegEx函数。

如何使用RegEx函数来解析此问题?

+1

是不是你在Main()中将字符串数组作为命令行参数? –

+0

不,我正在解析文件夹中的批处理文件。 – ChadD

+1

我不会使用正则表达式来处理这个问题。命令行中有太多特殊情况。你最好使用http://stackoverflow.com/questions/491595/best-way-to-parse-command-line-arguments-in-c?rq=1的建议之一,或者只是写你的自己的(这可能需要几个小时)。 –

回答

10

Jim Mischel的评论中的link指出,Win32 API为此提供了一个函数。我建议使用它来保持一致性。以下是一个示例(来自PInvoke)。

static string[] SplitArgs(string unsplitArgumentLine) 
{ 
    int numberOfArgs; 
    IntPtr ptrToSplitArgs; 
    string[] splitArgs; 

    ptrToSplitArgs = CommandLineToArgvW(unsplitArgumentLine, out numberOfArgs); 
    if (ptrToSplitArgs == IntPtr.Zero) 
     throw new ArgumentException("Unable to split argument.", 
      new Win32Exception()); 
    try 
    { 
     splitArgs = new string[numberOfArgs]; 
     for (int i = 0; i < numberOfArgs; i++) 
      splitArgs[i] = Marshal.PtrToStringUni(
       Marshal.ReadIntPtr(ptrToSplitArgs, i * IntPtr.Size)); 
     return splitArgs; 
    } 
    finally 
    { 
     LocalFree(ptrToSplitArgs); 
    } 
} 

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

[DllImport("kernel32.dll")] 
static extern IntPtr LocalFree(IntPtr hMem); 

如果你想快速和肮脏的,不灵活的,脆弱的正则表达式的解决方案,你可以做这样的事情:

var rex = new Regex(@"("".*?""|[^ ""]+)+"); 
string test = "CALL \"C:\\My File Name With Space\" /P1 P1Value /P1 P2Value"; 
var array = rex.Matches(test).OfType<Match>().Select(m => m.Groups[0]).ToArray(); 
+0

工作就像一个魅力。我很惊讶地发现代码不在框架之内。我觉得有点肮脏,不知道为什么,可能是因为我不明白。 – ChadD

+0

sqlcmd.exe(http://msdn.microsoft.com/en-us/library/ms162773.aspx)可能还有其他一些exes允许params开关以短划线的形式,后跟单个字母以前有一个可选空间编写参数值。例如,“sqlcmd.exe -sMyServer”和“sqlcmd.exe -s MyServer”表示相同的传递值。但是,这个函数为第一个传递了2个参数,第二个传递了3个参数。 – ChadD

+0

@ChadD - 'CommandLineToArgvW'是shell用来弄清楚如何传递参数的东西。 sqlcmd.exe然后包含解释它们的逻辑。 '-s MyServer'作为两个参数传递,但sqlcmd.exe将它们识别为一个选项。 – Chad

1

我不会用正则表达式做,上面显示各种原因。

如果我需要的话,这将匹配您的简单要求:

(".*?")|([^ ]+) 

然而,这还不包括:

  • 转义引号
  • 单引号
  • 非ascii引号(你不认为人们会把自己的文字粘贴到你的文件中)
  • 组合s的以上

而这只是我的头顶。

1

@chad亨德森你忘了包括单引号,这也有捕获任何引用之前的问题。

这里是包括单引号的更正,但也显示了报价之前额外捕获的问题。 http://regexhero.net/tester/?id=81cebbb2-5548-4973-be19-b508f14c3348

+0

这样的特殊情况Windows实际上不会像处理双引号一样处理单引号,而且您也不确定引号的类型在你的正则表达式:)为了好玩,我更新了我的支持形式'a“bc”d'的参数 – Chad

+0

我很好奇窗口对待单引号的方式与此有什么关系? –

+0

Windows将' 'a b'作为两个独立的论点,'a'和'b' – Chad