C# 将包含命令行参数的字符串拆分为 string[]
我有一个字符串,其中包含要传递给另一个可执行文件的命令行参数,并且我需要提取包含各个参数的 string[],其方式与在命令行上指定命令时使用 C# 的方式相同。 通过反射执行另一个程序集入口点时将使用 string[]。
有一个标准函数吗? 或者是否有正确分割参数的首选方法(正则表达式?)? 它必须正确处理可能包含空格的 '"' 分隔字符串,因此我不能只在 ' ' 上进行分割。
示例字符串:
string parameterString = @"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""[email protected]"" tasks:""SomeTask,Some Other Task"" -someParam foo";
示例结果:
string[] parameterArray = new string[] {
@"/src:C:\tmp\Some Folder\Sub Folder",
@"/users:[email protected]",
@"tasks:SomeTask,Some Other Task",
@"-someParam",
@"foo"
};
我不需要命令行解析库,只是获取 String[ 的一种方法] 应该生成。
更新:我必须更改预期结果以匹配 C# 实际生成的结果(删除了拆分字符串中的额外“”)
I have a single string that contains the command-line parameters to be passed to another executable and I need to extract the string[] containing the individual parameters in the same way that C# would if the commands had been specified on the command-line. The string[] will be used when executing another assemblies entry-point via reflection.
Is there a standard function for this? Or is there a preferred method (regex?) for splitting the parameters correctly? It must handle '"' delimited strings that may contain spaces correctly, so I can't just split on ' '.
Example string:
string parameterString = @"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""[email protected]"" tasks:""SomeTask,Some Other Task"" -someParam foo";
Example result:
string[] parameterArray = new string[] {
@"/src:C:\tmp\Some Folder\Sub Folder",
@"/users:[email protected]",
@"tasks:SomeTask,Some Other Task",
@"-someParam",
@"foo"
};
I do not need a command-line parsing library, just a way to get the String[] that should be generated.
Update: I had to change the expected result to match what is actually generated by C# (removed the extra "'s in the split strings)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(27)
Windows 命令行解析器的行为正如您所说,按空格分割,除非前面有未闭合的引号。 我建议你自己编写解析器。 也许是这样的:
The Windows command-line parser behaves just as you say, split on space unless there's a unclosed quote before it. I would recommend writing the parser yourself. Something like this maybe:
我从杰弗里那里得到了 答案L Whitledge 并对其进行了一些增强。
现在它支持单引号和双引号。 您可以通过使用其他类型的引号在参数本身中使用引号。
它还从参数中删除引号,因为它们对参数信息没有贡献。
I took the answer from Jeffrey L Whitledge and enhanced it a little.
It now supports both single and double quotes. You can use quotes in the parameters itself by using other typed quotes.
It also strips the quotes from the arguments since these do not contribute to the argument information.
良好且纯粹的托管解决方案 by Earwicker 无法处理这样的参数:
它返回了 3 个元素:
所以这里有一个修复来支持“引用” \"escape\" quote":
用另外 2 个案例进行测试:
还注意到 接受了 Atif Aziz 的答案,它使用 < a href="http://msdn.microsoft.com/en-us/library/bb776391.aspx" rel="nofollow noreferrer">CommandLineToArgvW 也失败。 它返回了 4 个元素:
希望这可以帮助将来寻找此类解决方案的人。
The good and pure managed solution by Earwicker failed to handle arguments like this:
It returned 3 elements:
So here is a fix to support the "quoted \"escape\" quote":
Tested with 2 additional cases:
Also noted that the accepted answer by Atif Aziz which uses CommandLineToArgvW also failed. It returned 4 elements:
Hope this helps someone looking for such a solution in the future.
我喜欢迭代器,现在 LINQ 使
IEnumerable
为可以轻松用作字符串数组,因此我遵循 Jeffrey L Whitledge 的答案 是(作为string
的扩展方法):I like iterators, and nowadays LINQ makes
IEnumerable<String>
as easily usable as arrays of string, so my take following the spirit of Jeffrey L Whitledge's answer is (as a extension method tostring
):Environment.GetCommandLineArgs()
Environment.GetCommandLineArgs()
在你的问题中,你要求使用正则表达式,我是它们的忠实粉丝和用户,所以当我需要像你一样进行同样的参数拆分时,我在谷歌搜索后没有找到简单的解决方案后编写了自己的正则表达式。 我喜欢简短的解决方案,所以我做了一个,如下所示:
它处理引号内的空格和引号,并将包含的“”转换为“。请随意使用该代码!
In your question you asked for a regex, and I am a big fan and user of them, so when I needed to do this same argument split as you, I wrote my own regex after googling around and not finding a simple solution. I like short solutions, so I made one and here it is:
It handles blanks and quotes inside quotation marks, and converts enclosed "" to ". Feel free to use the code!
哦,哎呀。 这都是……呃。 但是这个是合法的官方。 来自 Microsoft,使用 C# for .NET Core,也许仅限 Windows,也许跨平台,但 MIT 许可。
选择花絮、方法声明和值得注意的评论;
-
-
这是从.NET Framework 移植到.NET Core 的代码,我假设是MSVC C 库或
CommandLineToArgvW
。这是我用正则表达式处理一些恶作剧的半心半意的尝试,并忽略了零位参数。 这有点神奇。
在古怪的生成输出上对其进行了相当多的测试。 它的输出与猴子输入并通过 CommandLineToArgvW 运行的内容有相当一部分相匹配。
Oh heck. It's all ... Eugh. But this is legit official. From Microsoft in C# for .NET Core, maybe windows only, maybe cross-platform, but MIT licensed.
Select tidbits, method declarations and notable comments;
-
-
This is code ported to .NET Core from .NET Framework from what I assume is either the MSVC C library or
CommandLineToArgvW
.Here's my half-hearted attempt at handling some of the shenanigans with Regular Expressions, and ignoring the argument zero bit. It's a little bit wizardy.
Tested it a fair bit on wacky generated output. It's output matches a fair percentage of what the monkeys typed up and ran through
CommandLineToArgvW
.有一个 NuGet 包恰好包含您需要的功能:
Microsoft.CodeAnalysis.Common 包含类 CommandLineParser 使用方法 SplitCommandLineIntoArguments 。
你像这样使用它:
There's a NuGet package which contains exactly the functionality you need:
Microsoft.CodeAnalysis.Common contains the class CommandLineParser with the method SplitCommandLineIntoArguments.
You use it like this:
这篇代码项目文章是我过去使用过的。 这是一段很好的代码,但它可能会起作用。
这篇 MSDN 文章是我能找到的唯一解释 C# 的内容解析命令行参数。
This The Code Project article is what I've used in the past. It's a good bit of code, but it might work.
This MSDN article is the only thing I could find that explains how C# parses command line arguments.
纯托管解决方案可能会有所帮助。 WINAPI功能有太多“问题”注释,并且在其他平台上不可用。 这是我的代码,它具有明确定义的行为(如果您愿意,可以更改)。
它应该与 .NET/Windows 在提供 string[] args 参数时执行的操作相同,并且我已将其与许多“有趣”的值进行了比较。
这是一个经典的状态机实现,它从输入字符串中获取每个字符并将其解释为当前状态,生成输出和新状态。 状态在变量
escape
、inQuote
、hadQuote
和prevCh
中定义,输出收集在 <代码>currentArg和args
。我通过在真实命令提示符 (Windows 7) 上进行实验发现的一些特性:
\\
生成\
,\"
生成引用范围内的"
、""
会生成"
。^
字符似乎也很神奇:它不加倍时总是消失。否则它对真正的命令行没有影响,因为我还没有找到这种行为的模式。在这种模式中是以下命令:
cmd
命令似乎捕获了外部引号并逐字记录其余内容,其中一定有一些特殊的魔力,我没有对我的方法进行基准测试。但认为它相当快。它不使用
Regex
,也不执行任何字符串连接,而是使用StringBuilder
来收集参数的字符并将它们放入其中。一个列表。A purely managed solution might be helpful. There are too many "problem" comments for the WINAPI function and it's not available on other platforms. Here's my code that has a well-defined behaviour (that you can change if you like).
It should do the same as what .NET/Windows do when providing that
string[] args
parameter, and I've compared it with a number of "interesting" values.This is a classic state-machine implementation that takes each single character from the input string and interprets it for the current state, producing output and a new state. The state is defined in the variables
escape
,inQuote
,hadQuote
andprevCh
, and the output is collected incurrentArg
andargs
.Some of the specialties that I've discovered by experiments on a real command prompt (Windows 7):
\\
produces\
,\"
produces"
,""
within a quoted range produces"
.The
^
character seems to be magical, too: it always disappears when not doubling it. Otherwise it has no effect on a real command line. My implementation does not support this, as I haven't found a pattern in this behaviour. Maybe somebody knows more about it.Something that doesn't fit in this pattern is the following command:
The
cmd
command seems to catch the outer quotes and take the rest verbatim. There must be some special magic sauce in this.I've done no benchmarks on my method, but consider it reasonably fast. It doesn't use
Regex
and doesn't do any string concatenation but instead uses aStringBuilder
to collect the characters for an argument and puts them in a list.使用:
根据 Vapour in the Alley 的回答,这个也支持 ^ 转义。
示例:
它还支持多个空格(每个空格块仅中断参数一次)。
Use:
Based on Vapour in the Alley's answer, this one also supports ^ escapes.
Examples:
It also supports multiple spaces (breaks arguments just one time per block of spaces).
目前,这是我拥有的代码:
它不适用于转义引号,但适用于我迄今为止遇到的情况。
Currently, this is the code that I have:
It doesn't work with escaped quotes, but it works for the cases that I've come up against so far.
这是对 Anton 代码的回复,该代码不适用于转义引号。 我修改了3个地方。
This is a reply to Anton's code, which do not work with escaped quotes. I modified 3 places.
我认为 C# 应用程序没有单引号或 ^ 引号。
以下功能对我来说工作正常:
I don't think there are single quotes or ^ quotes for C# applications.
The following function is working fine for me:
您可以查看我昨天发布的代码:
[C#] 路径 & 参数字符串
它将文件名+参数拆分为字符串[]。 处理短路径、环境变量和丢失的文件扩展名。
(最初是针对注册表中的 UninstallString。)
You can have a look at the code I've posted yesterday:
[C#] Path & arguments strings
It splits a filename + arguments into string[]. Short paths, environment variables, and missing file extensions are handled.
(Initially it was for UninstallString in Registry.)
试试这个代码:
它是用葡萄牙语编写的。
Try this code:
It's written in Portuguese.
这是一个完成工作的一行(请参阅在 BurstCmdLineArgs(...) 方法内完成所有工作的一行)。
这不是我所说的最具可读性的代码行,但您可以为了可读性而将其分解。 它的目的很简单,并且不适用于所有参数情况(例如其中包含分割字符串字符分隔符的文件名参数)。
该解决方案在我使用它的解决方案中运行良好。 就像我说的,它不需要大量代码来处理每个可能的参数格式 n 阶乘,就可以完成工作。
Here's a one liner that gets the job done (see the one line that does all of the work inside the BurstCmdLineArgs(...) method).
Not what I'd call the most readable line of code, but you can break it out for readability's sake. It's simple on purpose and does not work well for all argument cases (like file name arguments that contain the split string character delimiter in them).
This solution has worked well in my solutions that use it. Like I said, it gets the job done without a rat's nest of code to handle every possible argument format n-factorial.
在这里找不到我喜欢的东西。 我讨厌用yield magic 来搞乱一个小命令行的堆栈(如果它是一个 TB 的流,那就是另一个故事了)。
这是我的看法,它支持使用双引号进行引号转义,如下所示:
结果:
Couldn't find anything I liked here. I hate to mess up the stack with yield magic for a small command-line (if it were a stream of a terabyte, it would be another story).
Here's my take, it supports quote escapes with double quotes like these:
result:
我已经实现了状态机,使其具有相同的解析器结果,就像将 args 传递到 .NET 应用程序并在
static void Main(string[] args)
方法中进行处理一样。I have implemented state machine to have same parser results as if args would be passed into .NET application and processed in
static void Main(string[] args)
method.以下是将空格(单个或多个空格)视为命令行参数分隔符并返回真正的命令行参数的解决方案:
Here is the solution which treats space(s) (single or multiple spaces) as command line parameter separator and returns the real command line arguments:
我编写了一个方法来将文件名与其参数分开,以便与需要分隔文件名和参数字符串的 ProcessStartInfo 一起使用。
例如
"C:\Users\Me\Something.exe" -a
将给出
{ "C:\Users\Me\Something.exe", "-a" }
作为结果代码如下:
I wrote a method to separate a file name from its arguments, for use with
ProcessStartInfo
which requires separating the file name and argument string.For instance
"C:\Users\Me\Something.exe" -a
would give
{ "C:\Users\Me\Something.exe", "-a" }
as a resultCode below:
这包含在
System.CommandLine.Parsing
包中无需导入大型代码分析包。
https:// learn.microsoft.com/en-us/dotnet/api/system.commandline.parsing.commandlinestringsplitter.split?view=system-commandline
This is included in the
System.CommandLine.Parsing
packageNo need to import the large code analysis package.
https://learn.microsoft.com/en-us/dotnet/api/system.commandline.parsing.commandlinestringsplitter.split?view=system-commandline
我不确定我是否理解你的意思,但是用作分隔符的字符的问题是否也可以在文本中找到? (除了它是用双“?”转义的)
如果是这样,我将创建一个
for
循环,并替换 <"> 的所有实例。 与 <|> 一起出现 (或另一个“安全”字符,但请确保它仅替换 <">,而不是 <"">迭代字符串后,我会像之前发布的那样,分割字符串,但现在在字符上<|>。
I am not sure if I understood you, but is the problem that the character used as splitter, is also to be found inside the text? (Except for that it is escaped with double "?)
If so, I would create a
for
loop, and replace all instances where <"> is present with <|> (or another "safe" character, but make sure that it only replaces <">, and not <"">After iterating the string, I would do as previously posted, split the string, but now on the character <|>.
是的,字符串对象有一个名为
Split()
的内置函数,该函数采用单个参数来指定要查找的字符作为分隔符,并返回一个字符串数组 (string[]),其中包含各个字符其中的价值观。Yes, the string object has a built in function called
Split()
that takes a single parameter specifying the character to look for as a delimiter, and returns an array of strings (string[]) with the individual values in it.令我烦恼的是,没有函数可以根据检查每个字符的函数来分割字符串。 如果有的话可以这样写:
既然这样写了,为什么不写必要的扩展方法呢。 好吧,你说服了我......
首先,我自己的 Split 版本需要一个函数来决定指定的字符是否应该分割字符串:
根据情况,它可能会产生一些空字符串,但也许该信息会在其他情况下很有用,因此我不会删除此函数中的空条目。
其次(更平常的是)一个小助手,它将从字符串的开头和结尾修剪一对匹配的引号。 它比标准的 Trim 方法更加挑剔 - 它只会从每一端修剪一个字符,并且不会仅从一端修剪:
我想您也需要一些测试。 好吧,那么好吧。 但这绝对是最后一件事! 首先是一个辅助函数,它将分割结果与预期的数组内容进行比较:
然后我可以编写这样的测试:这
是满足您要求的测试:
请注意,该实现具有额外的功能,它将删除参数周围的引号(如果出现这种情况)有道理(感谢 TrimMatchingQuotes 函数)。 我相信这是正常命令行解释的一部分。
It annoys me that there's no function to split a string based on a function that examines each character. If there was, you could write it like this:
Although having written that, why not write the necessary extension methods. Okay, you talked me into it...
Firstly, my own version of Split that takes a function that has to decide whether the specified character should split the string:
It may yield some empty strings depending on the situation, but maybe that information will be useful in other cases, so I don't remove the empty entries in this function.
Secondly (and more mundanely) a little helper that will trim a matching pair of quotes from the start and end of a string. It's more fussy than the standard Trim method - it will only trim one character from each end, and it will not trim from just one end:
And I suppose you'll want some tests as well. Well, alright then. But this must be absolutely the last thing! First a helper function that compares the result of the split with the expected array contents:
Then I can write tests like this:
Here's the test for your requirements:
Note that the implementation has the extra feature that it will remove quotes around an argument if that makes sense (thanks to the TrimMatchingQuotes function). I believe that's part of the normal command-line interpretation.
除了良好且纯粹的托管Earwicker 的解决方案,为了完整起见,可能值得一提的是,Windows 还提供了
CommandLineToArgvW
函数,用于将字符串分解为数组字符串数:从 C# 调用此 API 并在托管代码中解压生成的字符串数组的示例可以在“使用 CommandLineToArgvW() API 将命令行字符串转换为 Args[]。” 下面是相同代码的稍微简单的版本:
In addition to the good and pure managed solution by Earwicker, it may be worth mentioning, for sake of completeness, that Windows also provides the
CommandLineToArgvW
function for breaking up a string into an array of strings:An example of calling this API from C# and unpacking the resulting string array in managed code can be found at, “Converting Command Line String to Args[] using CommandLineToArgvW() API.” Below is a slightly simpler version of the same code:
因为我想要与 OP 相同的行为(与 Windows cmd 完全相同的方式分割字符串),所以我编写了一堆测试用例并测试了此处发布的答案:
“预期”值来自直接使用 cmd.exe 进行测试在我的机器(Win10 x64)和一个简单的打印程序上:
这些是结果:
因为没有答案似乎是正确的(至少基于我的用例)这是我的解决方案,它目前通过了所有测试用例(但如果有人有额外的(失败)极端情况请评论):
我用来生成测试结果的代码可以在此处找到
Because I wanted the same behavior as OP (split a string exactly the same as windows cmd would do it) I wrote a bunch of test cases and tested the here posted answers:
the "expected" value comes from directly testing it with cmd.exe on my machine (Win10 x64) and a simple print program:
These are the results:
Because no answer seemed correct (at least based on my use case) here is my solution, it currently passes all test cases (but if anyone has additional (failing) corner cases please comment):
The code I used to generate the test results can be found here