2013-06-11 21 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