Skip to content

Instantly share code, notes, and snippets.

@acken
Last active August 29, 2015 14:02
Show Gist options
  • Save acken/5825b4cf2c755b27f818 to your computer and use it in GitHub Desktop.
Save acken/5825b4cf2c755b27f818 to your computer and use it in GitHub Desktop.
Command string parser
// Takes a "quoted argument string ignoring \" escaped" arguments. Returns an array of arguments
let commandStringToArguments (cmd: string) =
// Checks whether a quote is lead by an escape char
let isUnescapedQuote (i, c) =
c.Equals('"') && (i.Equals(0) || (cmd |> Seq.toArray).[i-1] <> '\\')
// Get the start and end position of quoted strings
let quotedStrings =
cmd
|> Seq.toArray
|> Array.mapi (fun i c -> (i, c))
|> Array.filter (fun point -> isUnescapedQuote point)
|> Array.map (fun (i, c) -> i)
|> Seq.pairwise
|> Seq.toArray
|> Array.map (fun (s, e) -> (s+1, e-1))
// Checks if current position is inside a quoted string
let outsideQuotedString i =
let count =
quotedStrings
|> Array.filter (fun (sstart, send) -> i >= sstart && i <= send)
|> Array.length
count.Equals(0)
// Locate all unquoted words
let words =
cmd
|> Seq.toArray
|> Array.mapi (fun i c -> (i+1, c))
|> Array.filter (fun (i, c) -> c.Equals(' '))
|> Array.map (fun (i, c) -> i)
|> Array.filter (fun i -> outsideQuotedString i)
|> Array.append [|0|]
// Get start positions for all commands in command string
let startPositions =
words
|> Array.append (quotedStrings |> Array.map (fun (start, _) -> start))
|> Array.sort
|> Seq.distinct
|> Seq.toArray
// Parse out a list of commands from start and end position
startPositions
|> Array.mapi (fun i p ->
if i.Equals((startPositions |> Array.length)-1) then (p, cmd.Length)
else (p, startPositions.[i+1]-1))
|> Array.map (fun (s, e) -> cmd.Substring(s, e-s))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment