感谢@mp3ferret 有正确的想法。但是没有使用 的解决方案示例Environment.CommandLine
,因此我继续创建了一个OriginalCommandLine
类,该类将获取最初输入的命令行参数。
参数在tokenizer
正则表达式中定义为任何类型字符的双引号字符串,或非空白字符的未引用字符串。在带引号的字符串中,引号字符可以用反斜杠转义。 但是,后面的反斜杠后跟双引号,然后是空格将不会被转义。
我之所以选择由于空格而导致的转义例外是为了容纳以反斜杠结尾的引用路径。我相信您遇到实际想要转义双引号的情况的可能性要小得多。
代码
static public class OriginalCommandLine
{
static Regex tokenizer = new Regex(@"""(?:\\""(?!\s)|[^""])*""|[^\s]+");
static Regex unescaper = new Regex(@"\\("")(?!\s|$)");
static Regex unquoter = new Regex(@"^\s*""|""\s*$");
static Regex quoteTester = new Regex(@"^\s*""(?:\\""|[^""])*""\s*$");
static public string[] Parse(string commandLine = null)
{
return tokenizer.Matches(commandLine ?? Environment.CommandLine).Cast<Match>()
.Skip(1).Select(m => unescaper.Replace(m.Value, @"""")).ToArray();
}
static public string UnQuote(string text)
{
return (IsQuoted(text)) ? unquoter.Replace(text, "") : text;
}
static public bool IsQuoted(string text)
{
return text != null && quoteTester.Match(text).Success;
}
}
结果
正如您从下面的结果中看到的那样,上述方法修复维护了引号,同时更优雅地处理了您可能遇到的现实场景。
Test:
ConsoleApp1.exe foo1 notepad.exe "C:\Progra\"m Files\MyDocuments\" "C:\Program Files\bar.txt"
args[]:
[0]: foo1
[1]: notepad.exe
[2]: C:\Progra"m Files\MyDocuments" C:\Program
[3]: Files\bar.txt
CommandLine.Parse():
[0]: foo1
[1]: notepad.exe
[2]: "C:\Progra"m Files\MyDocuments\"
[3]: "C:\Program Files\bar.txt"
最后
我辩论过使用另一种方案来转义双引号。""
鉴于命令行经常处理反斜杠,我觉得使用更好。我保留了反斜杠转义方法,因为它向后兼容命令行参数的正常处理方式。
如果您想使用该方案,请对正则表达式进行以下更改:
static Regex tokenizer = new Regex(@"""(?:""""|[^""])*""|[^\s]+");
static Regex unescaper = new Regex(@"""""");
static Regex unquoter = new Regex(@"^\s*""|""\s*$");
static Regex quoteTester = new Regex(@"^\s*""(?:""""|[^""])*""\s*$");
如果您想更接近您的期望args
但引号完整,请更改两个正则表达式。仍然存在细微差别,将从我的解决方案"abc"d
返回。 abcd
args
[0] = "abc", [1] = d
static Regex tokenizer = new Regex(@"""(?:\\""|[^""])*""|[^\s]+");
static Regex unescaper = new Regex(@"\\("")");
如果您真的非常想获得与 相同数量的元素,args
请使用以下命令:
static Regex tokenizer = new Regex(@"(?:[^\s""]*""(?:\\""|[^""])*"")+|[^\s]+");
static Regex unescaper = new Regex(@"\\("")");
完全匹配的结果
Test: "zzz"zz"Zzz" asdasd zz"zzz" "zzz"
args OriginalCommandLine
------------- -------------------
[0]: zzzzzZzz [0]: "zzz"zz"Zzz"
[1]: asdasd [1]: asdasd
[2]: zzzzz [2]: zz"zzz"
[3]: zzz [3]: "zzz"