DarkLite1
DarkLite1

Reputation: 14705

Splitting a string on spaces but ignore section between double quotes

How is it possible to split this string:

$Arguments = '/NOGUI /DATE /EXPAND 4 /SIZEUNIT 3 /SORTTYPE 0 /EXCEL "S:\Test\Brecht\Log Test\Report 13.xlsx" /SHEETNAME "Data set" /SCANPATH "S:\My Folder"'

into the following array:

/NOGUI
/DATE
/EXPAND
4
/SIZEUNIT
3
/SORTTYPE
0
/EXCEL
"S:\Test\Brecht\Log Test\Report 13.xlsx"
/SHEETNAME
"Data set"
/SCANPATH
"S:\My Folder"

When using $Argument.split(' ') it also splits the double quoted strings, which is not desired. On the ScriptingGuy's blog, they explain what is possible. But I can't seem to find a way to ignore the strings between double quotes.

Upvotes: 3

Views: 3071

Answers (3)

mklement0
mklement0

Reputation: 437558

Given that your string is a list of arguments that is (also) syntax-compatible with command calls in cmd.exe, a pragmatic solution is to pass your string to cmd /c and take advantage of cmd.exe's ability to splits such lists into individual arguments via its internal for statement:

$ArgumentList = 
 '/NOGUI /DATE /EXPAND 4 /SIZEUNIT 3 /SORTTYPE 0 /EXCEL "S:\Test\Brecht\Log Test\Report 13.xlsx" /SHEETNAME "Data set" /SCANPATH "S:\My Folder"'

cmd /c "for %i in ($ArgumentList) do @echo %i"

Since PowerShell captures output from external-program calls line by line, assigning the result to a variable will automatically create an array of individual arguments - with "..." enclosures retained, as requested.

Note:

  • Due to interpretation by cmd.exe, the above would expand cmd.exe-style variable references such as %USERPROFILE% and would only recognize "" as an escaped " inside a "..." argument.

If, by contrast, the argument list is to be interpreted as one for PowerShell, you can employ an analogous technique with Write-Output and Invoke-Expression, though note that the latter is generally best avoided unless you fully control or implicitly trust the string being evaluated.

$ArgumentList = 
 '/NOGUI /DATE /EXPAND 4 /SIZEUNIT 3 /SORTTYPE 0 /EXCEL "S:\Test\Brecht\Log Test\Report 13.xlsx" /SHEETNAME "Data set" /SCANPATH "S:\My Folder"'

Invoke-Expression "Write-Output -- $ArgumentList"

Note:

  • Caveat: Due to interpretation by PowerShell, $-prefixed tokens are expanded, as are any embedded commands, whether enclosed in $(...) or just (...), and PowerShell's string-literal rules apply, so that both "" and `" - but not \" - are recognized as escaped " chars. inside "..." arguments.

  • This solution invariably removes any enclosing "..." from the individual arguments.


Finally, to offer concise solution based on PowerShell's regex-based -split and -match operators (and a verbatim here-string to provide the input):

$ArgumentList = 
 '/NOGUI /DATE /EXPAND 4 /SIZEUNIT 3 /SORTTYPE 0 /EXCEL "S:\Test\Brecht\Log Test\Report 13.xlsx" /SHEETNAME "Data set" /SCANPATH "S:\My Folder"'

$ArgumentList -split '(".*?"|\S+)' -match '\S'

Note:

  • With this simple approach, tokens with escaped, embedded " (e.g., "Nat ""King"" Cole", "Nat `"King`" Cole" or "Nat \"King\" Cole") are not supported.

  • As requested in your question, the enclosing " characters are retained in the elements of the result array.

    • If you'd like to remove them, use regex '"(.*?)"|(\S+)' instead, but note that the solution will then also eliminate any "" tokens from the result array.
      • If that is to be avoided, keep the original regex and place -replace '"(.*?)"', '$1' after -match '\S''
  • For an explanation of the approach see this answer to a related question in the context of also supporting single-quoted tokens.

Upvotes: 0

js2010
js2010

Reputation: 27423

Trying to match each element instead, based on [RESOLVED] Regex Split on Whitespace EXCEPT in single quotes-VBForums. So anything between double-quotes or non-whitespace. The -match operator can't do allmatches.

$Arguments | select-string '("[^"]*"|\S)+' -AllMatches | % matches | % value

/NOGUI
/DATE
/EXPAND
4
/SIZEUNIT
3
/SORTTYPE
0
/EXCEL
"S:\Test\Brecht\Log Test\Report 13.xlsx"
/SHEETNAME
"Data set"
/SCANPATH
"S:\My Folder"

You might need to delete the quotes:

$list = $list -replace '"'

Upvotes: 3

Ketanbhut
Ketanbhut

Reputation: 506

$Arguments = '/NOGUI /DATE /EXPAND 4 /SIZEUNIT 3 /SORTTYPE 0 /EXCEL "S:\Test\Brecht\Log Test\Report 13.xlsx" /SHEETNAME "Data set" /SCANPATH "S:\My Folder"'

$splitString = [regex]::Split( $Arguments, ' (?=(?:[^"]|"[^"]*")*$)' )
$splitString

Output:

/NOGUI
/DATE
/EXPAND
4
/SIZEUNIT
3
/SORTTYPE
0
/EXCEL
"S:\Test\Brecht\Log Test\Report 13.xlsx"
/SHEETNAME
"Data set"
/SCANPATH
"S:\My Folder"  

Upvotes: 10

Related Questions