Ça m'énerve qu'il n'y a pas de fonction pour diviser une chaîne basée sur une fonction qui examine chaque personnage. S'il y avait, vous pouvez l'écrire comme ceci:
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));
}
Bien qu'ayant écrit cela, pourquoi ne pas écrire les méthodes d'extension. Bon, vous avez parlé de moi...
Tout d'abord, ma propre version de Split qui prend une fonction qui doit décider si le caractère spécifié doit fractionner la chaîne:
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);
}
Il peut produire certains des chaînes vides en fonction de la situation, mais peut-être que l'information sera utile dans d'autres cas, donc je n'ai pas supprimer les entrées vides dans cette fonction.
Deuxièmement (et plus prosaïquement) une petite aide qui sera couper une paire de guillemets de début et de fin de chaîne. C'est plus pointilleux que la version standard et la méthode - il seulement de la garniture d'un caractère à partir de chaque extrémité, et il ne sera pas de la garniture à partir d'une seule fin:
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;
}
Et je suppose que vous aurez envie de certains tests. Bien, très bien. Mais ce doit être absolument la dernière chose! D'abord une fonction d'assistance qui compare le résultat de la scission avec le contenu du tableau:
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]);
}
Alors je peux écrire des tests de ce genre:
Test("");
Test("a", "a");
Test(" abc ", "abc");
Test("a b ", "a", "b");
Test("a b \"c d\"", "a", "b", "c d");
Voici le test de vos exigences:
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");
Notez que la mise en œuvre a la fonction supplémentaire que cela va enlever les guillemets autour d'un argument si cela a du sens (grâce à la TrimMatchingQuotes fonction). Je crois que c'est une partie de la commande normale de ligne de l'interprétation.