6

我正在使用以下代码使用参数启动另一个进程,这里我将字符串路径作为参数传递,路径返回为c:\documents 和 settings\\local settings:

string path = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)).FullName(); //path = c:\documents and settings\<username>\local settings

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = path;
Process.Start(startInfo);

我想将路径作为一个参数传递,一个完整的字符串。但我发现路径已被多个参数分隔,它实际上被每个空格分隔。在这种情况下,它将c:\documents作为第一个参数,第二个参数和 settings\\local作为第三个参数...

我想将它们作为一个参数而不是 4 个参数传递。怎么能做到这一点StartInfo.Argument

4

4 回答 4

7

我不确定它是否有效,但请尝试"在您的路径周围使用:

startInfo.Arguments = "\"" + path + "\"";

这将包含您的字符串",因此空格将被忽略。

于 2013-03-12T15:18:29.323 回答
5

Process 对象以与控制台完全相同的方式处理参数。使用双引号将任何包含空格的参数括起来:“\”c:\documents and settings\local settings\""。

一个好的提示是尝试使用您提供的任何参数从控制台运行该过程。这比从 Process 对象运行更容易理解错误反馈。

于 2013-03-12T15:20:14.067 回答
4

将你的论点用引号括起来:

startInfo.Arguments = "\"" + path + "\"";
于 2013-03-12T15:18:28.713 回答
4

规则

此处记录了解析转义的规则:https ://msdn.microsoft.com/en-us/library/17w5ykft.aspx

Microsoft C/C++ 启动代码在解释操作系统命令行上给出的参数时使用以下规则:

  1. 参数由空格分隔,空格可以是空格,也可以是制表符。

  2. 插入字符 (^) 未被识别为转义字符或分隔符。该字符在传递到程序中的 argv 数组之前完全由操作系统中的命令行解析器处理。

  3. 由双引号 ("string") 包围的字符串被解释为单个参数,无论其中包含什么空格。带引号的字符串可以嵌入到参数中。

  4. 前面有反斜杠 (\") 的双引号被解释为文字双引号字符 (")。
  5. 反斜杠按字面意思解释,除非它们紧跟在双引号之前。
  6. 如果偶数个反斜杠后跟双引号,则在 argv 数组中为每对反斜杠放置一个反斜杠,并将双引号解释为字符串分隔符。
  7. 如果奇数个反斜杠后跟双引号,则每对反斜杠在 argv 数组中放置一个反斜杠,双引号被剩余的反斜杠“转义”,导致文字双引号(“ ) 放置在 argv 中。

应用于生成

不幸的是,没有关于如何正确转义参数的良好文档,即如何应用上述规则以确保将参数数组正确传递给目标应用程序。以下是我转义每个参数时遵循的规则:

  1. 如果参数包含空格或制表符,请将其括在 "(双引号)字符中。

  2. 如果参数包含 "(双引号),前面有 \(反斜杠)字符,则在附加转义的 "(双引号)之前用 \(反斜杠)转义前面的 \(反斜杠)字符。

  3. 如果参数以一个或多个 \(反斜杠)结尾,并且包含空格,请在添加封闭的 "(双引号)之前使用 \(反斜杠)转义最后的 \(反斜杠)字符。

编码

/// <summary>
/// Convert an argument array to an argument string for using
/// with Process.StartInfo.Arguments.
/// </summary>
/// <param name="argument">
/// The args to convert.
/// </param>
/// <returns>
/// The argument <see cref="string"/>.
/// </returns>
public static string EscapeArguments(string argument)
{
    using (var characterEnumerator = argument.GetEnumerator())
    {
        var escapedArgument = new StringBuilder();
        var backslashCount = 0;
        var needsQuotes = false;

        while (characterEnumerator.MoveNext())
        {
            switch (characterEnumerator.Current)
            {
                case '\\':
                    // Backslashes are simply passed through, except when they need
                    // to be escaped when followed by a \", e.g. the argument string
                    // \", which would be encoded to \\\"
                    backslashCount++;
                    escapedArgument.Append('\\');
                    break;

                case '\"':
                    // Escape any preceding backslashes
                    for (var c = 0; c < backslashCount; c++)
                    {
                        escapedArgument.Append('\\');
                    }

                    // Append an escaped double quote.
                    escapedArgument.Append("\\\"");

                    // Reset the backslash counter.
                    backslashCount = 0;
                    break;

                case ' ':
                case '\t':
                    // White spaces are escaped by surrounding the entire string with
                    // double quotes, which should be done at the end to prevent 
                    // multiple wrappings.
                    needsQuotes = true;

                    // Append the whitespace
                    escapedArgument.Append(characterEnumerator.Current);

                    // Reset the backslash counter.
                    backslashCount = 0;
                    break;

                default:
                    // Reset the backslash counter.
                    backslashCount = 0;

                    // Append the current character
                    escapedArgument.Append(characterEnumerator.Current);
                    break;
            }
        }

        // No need to wrap in quotes
        if (!needsQuotes)
        {
            return escapedArgument.ToString();
        }

        // Prepend the "
        escapedArgument.Insert(0, '"');

        // Escape any preceding backslashes before appending the "
        for (var c = 0; c < backslashCount; c++)
        {
            escapedArgument.Append('\\');
        }

        // Append the final "
        escapedArgument.Append('\"');

        return escapedArgument.ToString();
    }
}

/// <summary>
/// Convert an argument array to an argument string for using
/// with Process.StartInfo.Arguments.
/// </summary>
/// <param name="args">
/// The args to convert.
/// </param>
/// <returns>
/// The argument <see cref="string"/>.
/// </returns>
public static string EscapeArguments(params string[] args)
{
    var argEnumerator = args.GetEnumerator();
    var arguments = new StringBuilder();

    if (!argEnumerator.MoveNext())
    {
        return string.Empty;
    }

    arguments.Append(EscapeArguments((string)argEnumerator.Current));

    while (argEnumerator.MoveNext())
    {
        arguments.Append(' ');
        arguments.Append(EscapeArguments((string)argEnumerator.Current));
    }

    return arguments.ToString();
}

测试用例

这是我在验证上述代码时使用的测试用例(线束留给读者作为练习)

注意:我的测试用例是将以下情况的随机数作为输入 args 数组,将其编码为参数字符串,将字符串传递给将参数作为 JSON 数组输出的新进程,并验证输入 args数组匹配输出 JSON 数组。

+----------------------------------------+--------- ----------------------------------+
| 输入字符串 | 转义字符串 |
+----------------------------------------+--------- ----------------------------------+
| 引用的论点 | “引用的论点” |
| "报价 | \"报价 |
| "包装报价" | \"包装报价\" |
| “引用包装报价” | "\"引用包装的报价\"" |
| \反斜杠文字 | \反斜杠文字 |
| \\doubleBackslashLiteral | \\doubleBackslashLiteral |
| 尾随反斜杠\ | 尾随反斜杠\ |
| 双尾反斜杠\\ | 双尾反斜杠\\ |
| \ 带引号的反斜杠文字 | "\ 引用的反斜杠文字" |
| \\ 引用的双反斜杠文字 | "\\ 引用的双反斜杠文字" |
| 引用的尾随反斜杠\ | "引用尾随反斜杠\\" |
| 带引号的双尾反斜杠\\ | "引用的双尾反斜杠\\\\" |
| \"\backslashQuoteEscaping | "\\\"\backslashQuoteEscaping " |
| \\"\doubleBackslashQuoteEscaping | "\\\\\"\doubleBackslashQuoteEscaping " |
| \\"\\doubleBackslashQuoteEscaping | "\\\\"\\doubleBackslashQuoteEscaping " |
| \"\\doubleBackslashQuoteEscaping | "\\\"\\doubleBackslashQuoteEscaping " |
| \"\反斜杠引号转义 | "\\\"\反斜杠引号转义" |
| \\"\双反斜杠引号转义 | "\\\\\\"\双反斜杠引号转义" |
| \\"\\双反斜杠引号转义 | "\\\\\"\\双反斜杠引号转义" |
| \"\\双反斜杠引号转义 | "\\\"\\双反斜杠引号转义" |
| TrailingQuoteEscaping" | TrailingQuoteEscaping\" |
| TrailingQuoteEscaping\" | TrailingQuoteEscaping\\\" |
| TrailingQuoteEscaping\"\ | TrailingQuoteEscaping\\\"\ |
| TrailingQuoteEscaping"\ | TrailingQuoteEscaping\"\ |
| 尾随引号转义" | "尾随引号转义\"" |
| 尾随引号转义\" | "尾随引号转义\\\"" |
| 尾随引号转义\"\ | "尾随引号转义\\\"\\" |
| 尾随引号转义"\ | "尾随引号转义\"\\" |
+----------------------------------------+--------- ----------------------------------+

关于这个问题,这里还有其他答案。我只是更喜欢编码状态机而不是正则表达式(而且,它运行得更快)。 https://stackoverflow.com/a/6040946/3591916很好地解释了如何做到这一点。

于 2016-10-30T21:55:58.993 回答