Es ärgert mich, dass es keine Funktion gibt, eine Zeichenfolge basierend auf einer Funktion zu teilen, die jedes Zeichen untersucht. Wenn ja, könnten Sie es so schreiben:
public static IEnumerable<string> SplitCommandLine(string commandLine)
{
bool inQuotes = false;
return commandLine.Split(c =>
{
if (c == '\"')
inQuotes = !inQuotes;
return !inQuotes && c == ' ';
})
.Select(arg => arg.Trim().TrimMatchingQuotes('\"'))
.Where(arg => !string.IsNullOrEmpty(arg));
}
Obwohl Sie das geschrieben haben, warum nicht die notwendigen Erweiterungsmethoden schreiben? Okay, du hast mich dazu überredet ...
Erstens meine eigene Version von Split, die eine Funktion übernimmt, die entscheiden muss, ob das angegebene Zeichen die Zeichenfolge teilen soll:
public static IEnumerable<string> Split(this string str,
Func<char, bool> controller)
{
int nextPiece = 0;
for (int c = 0; c < str.Length; c++)
{
if (controller(str[c]))
{
yield return str.Substring(nextPiece, c - nextPiece);
nextPiece = c + 1;
}
}
yield return str.Substring(nextPiece);
}
Abhängig von der Situation kann es zu leeren Zeichenfolgen kommen, aber in anderen Fällen sind diese Informationen möglicherweise hilfreich, sodass ich die leeren Einträge in dieser Funktion nicht entferne.
Zweitens (und allgemeiner) ein kleiner Helfer, der ein passendes Zitatpaar vom Anfang und Ende einer Zeichenfolge abschneidet. Es ist pingeliger als die Standard-Trimmmethode - es schneidet nur ein Zeichen von jedem Ende und nicht nur von einem Ende:
public static string TrimMatchingQuotes(this string input, char quote)
{
if ((input.Length >= 2) &&
(input[0] == quote) && (input[input.Length - 1] == quote))
return input.Substring(1, input.Length - 2);
return input;
}
Und ich nehme an, Sie möchten auch einige Tests. Na gut dann. Aber das muss absolut das Letzte sein! Zuerst eine Hilfsfunktion, die das Ergebnis der Aufteilung mit dem erwarteten Array-Inhalt vergleicht:
public static void Test(string cmdLine, params string[] args)
{
string[] split = SplitCommandLine(cmdLine).ToArray();
Debug.Assert(split.Length == args.Length);
for (int n = 0; n < split.Length; n++)
Debug.Assert(split[n] == args[n]);
}
Dann kann ich solche Tests schreiben:
Test("");
Test("a", "a");
Test(" abc ", "abc");
Test("a b ", "a", "b");
Test("a b \"c d\"", "a", "b", "c d");
Hier ist der Test für Ihre Anforderungen:
Test(@"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""abcdefg@hijkl.com"" tasks:""SomeTask,Some Other Task"" -someParam",
@"/src:""C:\tmp\Some Folder\Sub Folder""", @"/users:""abcdefg@hijkl.com""", @"tasks:""SomeTask,Some Other Task""", @"-someParam");
Beachten Sie, dass die Implementierung die zusätzliche Funktion hat, Anführungszeichen um ein Argument zu entfernen, wenn dies sinnvoll ist (dank der TrimMatchingQuotes-Funktion). Ich glaube, das ist Teil der normalen Befehlszeileninterpretation.