反斜杠并在命令行参数中引用

Myk*_*huk 20 .net c#

以下行为是C#.NET中的某些功能还是错误?

测试应用:

using System;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Arguments:");
            foreach (string arg in args)
            {
                Console.WriteLine(arg);
            }

            Console.WriteLine();
            Console.WriteLine("Command Line:");
            var clArgs = Environment.CommandLine.Split(' ');
            foreach (string arg in clArgs.Skip(clArgs.Length - args.Length))
            {
                Console.WriteLine(arg);
            }

            Console.ReadKey();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用命令行参数运行它:

a "b" "\\x\\" "\x\"
Run Code Online (Sandbox Code Playgroud)

在我收到的结果中:

Arguments:
a
b
\\x\
\x"

Command Line:
a
"b"
"\\x\\"
"\x\"
Run Code Online (Sandbox Code Playgroud)

传递给方法Main()的args中缺少反斜杠和未删除的引号.除手动解析外,正确的解决方法是什么Environment.CommandLine

nyb*_*ler 19

根据Jon Galloway的这篇文章,在命令行参数中使用反斜杠时可能会遇到奇怪的行为.

最引人注目的是它提到" 大多数应用程序(包括.NET应用程序)使用CommandLineToArgvW来解码它们的命令行.它使用疯狂的转义规则来解释你所看到的行为. "

它解释了第一组反斜杠不需要转义,但是alpha(也许是数字?)字符后面的反斜杠需要转义,并且引号总是需要转义.

根据这些规则,我相信你得到你想要的论据,你必须将它们传递给:

a "b" "\\x\\\\" "\x\\"
Run Code Online (Sandbox Code Playgroud)

确实是"哇哇".

  • 对于未来的读者:[CommandLineToArgvW文档](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391.aspx)要么是误导性的,要么是恕我直言.幸运的是,CommandLineToArgvW和.Net的行为与[VS文档](https://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft.aspx)描述的完全相同.更好的描述:[每个人都以错误的方式引用命令行参数](https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way /) (2认同)

Tae*_*ost 6

前几天我遇到了同样的问题,并且很难解决。在我的谷歌搜索中,我发现了这篇关于 VB.NET(我的应用程序的语言)的文章,它解决了问题,而无需根据参数更改任何其他代码。

在那篇文章中,他引用了为 C# 编写的原始文章。这是实际的代码,你传递它Environment.CommandLine()

C#

class CommandLineTools
{
    /// <summary>
    /// C-like argument parser
    /// </summary>
    /// <param name="commandLine">Command line string with arguments. Use Environment.CommandLine</param>
    /// <returns>The args[] array (argv)</returns>
    public static string[] CreateArgs(string commandLine)
    {
        StringBuilder argsBuilder = new StringBuilder(commandLine);
        bool inQuote = false;

        // Convert the spaces to a newline sign so we can split at newline later on
        // Only convert spaces which are outside the boundries of quoted text
        for (int i = 0; i < argsBuilder.Length; i++)
        {
            if (argsBuilder[i].Equals('"'))
            {
                inQuote = !inQuote;
            }

            if (argsBuilder[i].Equals(' ') && !inQuote)
            {
                argsBuilder[i] = '\n';
            }
        }

        // Split to args array
        string[] args = argsBuilder.ToString().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

        // Clean the '"' signs from the args as needed.
        for (int i = 0; i < args.Length; i++)
        {
            args[i] = ClearQuotes(args[i]);
        }

        return args;
    }

    /// <summary>
    /// Cleans quotes from the arguments.<br/>
    /// All signle quotes (") will be removed.<br/>
    /// Every pair of quotes ("") will transform to a single quote.<br/>
    /// </summary>
    /// <param name="stringWithQuotes">A string with quotes.</param>
    /// <returns>The same string if its without quotes, or a clean string if its with quotes.</returns>
    private static string ClearQuotes(string stringWithQuotes)
    {
        int quoteIndex;
        if ((quoteIndex = stringWithQuotes.IndexOf('"')) == -1)
        {
            // String is without quotes..
            return stringWithQuotes;
        }

        // Linear sb scan is faster than string assignemnt if quote count is 2 or more (=always)
        StringBuilder sb = new StringBuilder(stringWithQuotes);
        for (int i = quoteIndex; i < sb.Length; i++)
        {
            if (sb[i].Equals('"'))
            {
                // If we are not at the last index and the next one is '"', we need to jump one to preserve one
                if (i != sb.Length - 1 && sb[i + 1].Equals('"'))
                {
                    i++;
                }

                // We remove and then set index one backwards.
                // This is because the remove itself is going to shift everything left by 1.
                sb.Remove(i--, 1);
            }
        }

        return sb.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

VB.NET:

Imports System.Text

' Original version by Jonathan Levison (C#)'
' http://sleepingbits.com/2010/01/command-line-arguments-with-double-quotes-in-net/
' converted using http://www.developerfusion.com/tools/convert/csharp-to-vb/
' and then some manual effort to fix language discrepancies
Friend Class CommandLineHelper


    ''' <summary>
    ''' C-like argument parser
    ''' </summary>
    ''' <param name="commandLine">Command line string with arguments. Use Environment.CommandLine</param>
    ''' <returns>The args[] array (argv)</returns>
    Public Shared Function CreateArgs(commandLine As String) As String()
        Dim argsBuilder As New StringBuilder(commandLine)
        Dim inQuote As Boolean = False

        ' Convert the spaces to a newline sign so we can split at newline later on
        ' Only convert spaces which are outside the boundries of quoted text
        For i As Integer = 0 To argsBuilder.Length - 1
            If argsBuilder(i).Equals(""""c) Then
                inQuote = Not inQuote
            End If

            If argsBuilder(i).Equals(" "c) AndAlso Not inQuote Then
                argsBuilder(i) = ControlChars.Lf
            End If
        Next

        ' Split to args array
        Dim args As String() = argsBuilder.ToString().Split(New Char() {ControlChars.Lf}, StringSplitOptions.RemoveEmptyEntries)

        ' Clean the '"' signs from the args as needed.
        For i As Integer = 0 To args.Length - 1
            args(i) = ClearQuotes(args(i))
        Next

        Return args
    End Function


    ''' <summary>
    ''' Cleans quotes from the arguments.<br/>
    ''' All signle quotes (") will be removed.<br/>
    ''' Every pair of quotes ("") will transform to a single quote.<br/>
    ''' </summary>
    ''' <param name="stringWithQuotes">A string with quotes.</param>
    ''' <returns>The same string if its without quotes, or a clean string if its with quotes.</returns>
    Private Shared Function ClearQuotes(stringWithQuotes As String) As String
        Dim quoteIndex As Integer = stringWithQuotes.IndexOf(""""c)
        If quoteIndex = -1 Then Return stringWithQuotes

        ' Linear sb scan is faster than string assignemnt if quote count is 2 or more (=always)
        Dim sb As New StringBuilder(stringWithQuotes)
        Dim i As Integer = quoteIndex
        Do While i < sb.Length
            If sb(i).Equals(""""c) Then
                ' If we are not at the last index and the next one is '"', we need to jump one to preserve one
                If i <> sb.Length - 1 AndAlso sb(i + 1).Equals(""""c) Then
                    i += 1
                End If

                ' We remove and then set index one backwards.
                ' This is because the remove itself is going to shift everything left by 1.
                sb.Remove(System.Math.Max(System.Threading.Interlocked.Decrement(i), i + 1), 1)
            End If
            i += 1
        Loop

        Return sb.ToString()
    End Function
End Class
Run Code Online (Sandbox Code Playgroud)