简体   繁体   English

除非在单引号或双引号中,否则如何用空格分隔字符串

[英]How do I split a string by spaces except if in single or double quotes

I realize this question has been asked many times here.我意识到这个问题已经在这里被问过很多次了。 I have looked at and tried many of the answers but none of them work for me.我已经查看并尝试了许多答案,但没有一个对我有用。

I am creating an application using C# that can accept command line arguments.我正在使用 C# 创建一个可以接受命令行 arguments 的应用程序。 eg例如

  1. Start -p:SomeNameValue -h
  2. DisplayMessage -m:Hello
  3. DisplayMessage -m:'Hello World'
  4. DisplayMessage -m:"Hello World"

My args come in as a single string.我的 args 以单个字符串的形式出现。 I need to split by spaces except where there are single or double quotes.我需要用空格分隔,除非有单引号或双引号。 So the above would end up as所以上面的结果会是

  1. Start -p:SomeNameValue -h Start -p:SomeNameValue -h
  2. DisplayMessage -m:Hello DisplayMessage -m:Hello
  3. DisplayMessage -m:'Hello World' DisplayMessage -m:'Hello World'
  4. DisplayMessage -m:"Hello World" DisplayMessage -m:"Hello World"

The answers I have found on here seem to break.我在这里找到的答案似乎被打破了。 eg They remove the : character or just don't work at all.例如,他们删除:字符或者根本不工作。 Some of the code I've tried as follows:我尝试过的一些代码如下:

var res1 = Regex.Matches(payload, @"[\""].+?[\""]|[^ ]+")
    .Cast<Match>()
    .Select(m => m.Value)
    .ToList();
var res2 = payload.Split('"')
    .Select((element, index) => index % 2 == 0  
        ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
        : new string[] { element })  // Keep the entire item
    .SelectMany(element => element).ToList();
var res3 = Regex
    .Matches(payload, @"\w+|""[\w\s]*""")
    .Cast<Match>()
    .Select(m => m.Groups["match"].Value)
    .ToList();
string[] res4 = Regex.Split(payload, ",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
Regex regex = new Regex(@"\w+|""[\w\s]*""");
var res5 = regex.Matches(payload).Cast<Match>().ToList();

I simply want to split the arg into blocks as per above.我只是想按照上面的方法将 arg 分成块。

Here is a simple demo program that I think does exactly what you want by parsing the string.这是一个简单的演示程序,我认为它通过解析字符串完全符合您的要求。

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {       
        string[] testStrings = new string[] {
            "Start -p:SomeNameValue -h",
            "DisplayMessage -m:Hello",
            "DisplayMessage -m:'Hello World'",
            "DisplayMessage -m:\"Hello World\"",
            "DisplayMessage -m:\"'Inside double quotes'\"",
            "DisplayMessage -m:'\"Inside single quotes\"'"              
        };

        foreach (string str in testStrings)
        {
            Console.WriteLine(str);
            string[] parsedStrings = ParseString(str);

            for (int i = 0; i < parsedStrings.Length; i++)
            {
                Console.WriteLine("    " + (i + 1) + ". " + parsedStrings[i]);              
            }
            Console.WriteLine();
        }
    }

    private static string[] ParseString(string str)
    {
        var retval = new List<string>();
        if (String.IsNullOrWhiteSpace(str)) return retval.ToArray();
        int ndx = 0;
        string s = "";
        bool insideDoubleQuote = false;
        bool insideSingleQuote = false;

        while (ndx < str.Length)
        {
            if (str[ndx] == ' ' && !insideDoubleQuote && !insideSingleQuote)
            {
                if (!String.IsNullOrWhiteSpace(s.Trim())) retval.Add(s.Trim());
                s = "";
            }
            if (str[ndx] == '"') insideDoubleQuote = !insideDoubleQuote;
            if (str[ndx] == '\'') insideSingleQuote = !insideSingleQuote;
            s += str[ndx];
            ndx++;
        }
        if (!String.IsNullOrWhiteSpace(s.Trim())) retval.Add(s.Trim());
        return retval.ToArray();
    }
}

This program will produce the following output:该程序将产生以下 output:

Start -p:SomeNameValue -h

1. Start

2. -p:SomeNameValue

3. -h

DisplayMessage -m:Hello

1. DisplayMessage

2. -m:Hello

DisplayMessage -m:'Hello World'

1. DisplayMessage

2. -m:'Hello World'

DisplayMessage -m:"Hello World"

1. DisplayMessage

2. -m:"Hello World"

DisplayMessage -m:"'Inside double quotes'"

1. DisplayMessage

2. -m:"'Inside double quotes'"

DisplayMessage -m:'"Inside single quotes"'

1. DisplayMessage

2. -m:'"Inside single quotes"'

One way to do this would be to use a loop to check for items that contain the double-quote delimiter and use a flag variable to determine if we're inside or outside a quoted string.一种方法是使用循环来检查包含双引号分隔符的项目,并使用标志变量来确定我们是在带引号的字符串内部还是外部。 If we're inside the quoted string, add the current part to a temporary variable.如果我们在带引号的字符串中,请将当前部分添加到临时变量中。 When we exit the quoted string, add the temporary variable to our arguments collection.当我们退出引用的字符串时,将临时变量添加到我们的 arguments 集合中。

I think the code is more self-explanatory.我认为代码更不言自明。 Note that I'm only allowing double quotes to delimit an argument with spaces.请注意,我只允许双引号用空格分隔参数。 If you want to allow single quotes as well, it's something you can add to the code:如果您也想允许单引号,则可以将其添加到代码中:

public static List<string> GetArgs(string cmdLine)
{
    var args = new List<string>();
    if (string.IsNullOrWhiteSpace(cmdLine)) return args;

    var parts = cmdLine.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
    var openQuote = false;
    var currentPart = new StringBuilder();

    foreach (var part in parts)
    {
        if (part.Count(c => c == '"') % 2 == 1)
        {
            if (currentPart.Length > 0) currentPart.Append(" ");
            currentPart.Append(part);

            if (openQuote)
            {
                args.Add(currentPart.ToString());
                currentPart.Clear();
            }

            openQuote = !openQuote;
        }
        else if (openQuote)
        {
            if (currentPart.Length > 0) currentPart.Append(" ");
            currentPart.Append(part);
        }
        else
        {
            args.Add(part);
        }
    }

    if (currentPart.Length > 0) args.Add(currentPart.ToString());

    return args;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM