Skip to content

Commit cccae2d

Browse files
committed
Add ParseArg method to split commandline
1 parent 000b156 commit cccae2d

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

src/CommandLine/UnParserExtensions.cs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System;
44
using System.Collections;
5+
using System.Collections.Generic;
56
using System.Linq;
67
using System.Text;
78
using CommandLine.Core;
@@ -102,6 +103,18 @@ public static string FormatCommandLine<T>(this Parser parser, T options)
102103
return parser.FormatCommandLine(options, config => { });
103104
}
104105

106+
/// <summary>
107+
/// Format a command line argument string from a parsed instance in the form of string[].
108+
/// </summary>
109+
/// <typeparam name="T">Type of <paramref name="options"/>.</typeparam>
110+
/// <param name="parser">Parser instance.</param>
111+
/// <param name="options">A parsed (or manually correctly constructed instance).</param>
112+
/// <returns>A string[] with command line arguments.</returns>
113+
public static string[] FormatCommandLineArgs<T>(this Parser parser, T options)
114+
{
115+
return parser.FormatCommandLine(options, config => { }).SplitArgs();
116+
}
117+
105118
/// <summary>
106119
/// Format a command line argument string from a parsed instance.
107120
/// </summary>
@@ -180,7 +193,19 @@ orderby v.Index
180193
return builder
181194
.ToString().TrimEnd(' ');
182195
}
183-
196+
/// <summary>
197+
/// Format a command line argument string[] from a parsed instance.
198+
/// </summary>
199+
/// <typeparam name="T">Type of <paramref name="options"/>.</typeparam>
200+
/// <param name="parser">Parser instance.</param>
201+
/// <param name="options">A parsed (or manually correctly constructed instance).</param>
202+
/// <param name="configuration">The <see cref="Action{UnParserSettings}"/> lambda used to configure
203+
/// aspects and behaviors of the unparsersing process.</param>
204+
/// <returns>A string[] with command line arguments.</returns>
205+
public static string[] FormatCommandLineArgs<T>(this Parser parser, T options, Action<UnParserSettings> configuration)
206+
{
207+
return FormatCommandLine<T>(parser, options, configuration).SplitArgs();
208+
}
184209
private static string FormatValue(Specification spec, object value)
185210
{
186211
var builder = new StringBuilder();
@@ -273,5 +298,35 @@ private static bool IsEmpty(this object value, Specification specification, bool
273298
if (value is IEnumerable && !((IEnumerable)value).GetEnumerator().MoveNext()) return true;
274299
return false;
275300
}
301+
302+
303+
#region splitter
304+
/// <summary>
305+
/// Returns a string array that contains the substrings in this instance that are delimited by space considering string between double quote.
306+
/// </summary>
307+
/// <param name="command">the commandline string</param>
308+
/// <param name="keepQuote">don't remove the quote</param>
309+
/// <returns>a string array that contains the substrings in this instance</returns>
310+
public static string[] SplitArgs(this string command, bool keepQuote = false)
311+
{
312+
if (string.IsNullOrEmpty(command))
313+
return new string[0];
314+
315+
var inQuote = false;
316+
var chars = command.ToCharArray().Select(v =>
317+
{
318+
if (v == '"')
319+
inQuote = !inQuote;
320+
return !inQuote && v == ' ' ? '\n' : v;
321+
}).ToArray();
322+
323+
return new string(chars).Split('\n')
324+
.Select(x => keepQuote ? x : x.Trim('"'))
325+
.Where(x => !string.IsNullOrWhiteSpace(x))
326+
.ToArray();
327+
}
328+
329+
#endregion
330+
276331
}
277332
}

tests/CommandLine.Tests/Unit/UnParserExtensionsTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,30 @@ public static void UnParsing_instance_with_nullable_bool(bool? flag, string expe
250250
.FormatCommandLine(options)
251251
.Should().BeEquivalentTo(expected);
252252
}
253+
#region SplitArgs
254+
[Theory]
255+
[InlineData("--shape Circle", new[] { "--shape","Circle" })]
256+
[InlineData(" --shape Circle ", new[] { "--shape", "Circle" })]
257+
[InlineData("-a --shape Circle", new[] {"-a", "--shape", "Circle" })]
258+
[InlineData("-a --shape Circle -- -x1 -x2", new[] { "-a", "--shape", "Circle","--","-x1","-x2" })]
259+
[InlineData("--name \"name with space and quote\" -x1", new[] { "--name", "name with space and quote","-x1" })]
260+
public static void Split_arguments(string command, string[] expectedArgs)
261+
{
262+
var args = command.SplitArgs();
263+
args.Should().BeEquivalentTo(expectedArgs);
264+
}
265+
[Theory]
266+
[InlineData("--shape Circle", new[] { "--shape", "Circle" })]
267+
[InlineData(" --shape Circle ", new[] { "--shape", "Circle" })]
268+
[InlineData("-a --shape Circle", new[] { "-a", "--shape", "Circle" })]
269+
[InlineData("-a --shape Circle -- -x1 -x2", new[] { "-a", "--shape", "Circle", "--", "-x1", "-x2" })]
270+
[InlineData("--name \"name with space and quote\" -x1", new[] { "--name", "\"name with space and quote\"", "-x1" })]
271+
public static void Split_arguments_with_keep_quote(string command, string[] expectedArgs)
272+
{
273+
var args = command.SplitArgs(true);
274+
args.Should().BeEquivalentTo(expectedArgs);
275+
}
276+
#endregion
253277
class Option_Int_Nullable
254278
{
255279
[Option('v', Default = 1)]

0 commit comments

Comments
 (0)