需要RegEx或其他方式来分隔包含转义引号的带引号标记

本文关键字:转义 包含 RegEx 其他 方式 分隔 需要 | 更新日期: 2023-09-27 18:25:07

基本上,我的任务是解析这个命令行:

-p "This is a string ""with quotes""" d:'1.txt "d:'some folder'1.out"

我需要的是将这个字符串拆分为:

  1. -p
  2. 这是一个"带引号"的字符串
  3. d: ''1.text
  4. d: ''一些文件夹''1.out

我搜索过(是的,我真的搜索过),但我找到的所有例子要么都没有包含转义引号,要么都使用了''"作为转义符。

需要RegEx或其他方式来分隔包含转义引号的带引号标记

我会使用真正的csv解析器,例如.NET中唯一可用的解析器:

string str = "-p '"This is a string '"'"with quotes'"'"'" d:''1.txt '"d:''some folder''1.out'"";
var allLineFields = new List<string[]>();
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(new StringReader(str)))
{
    parser.Delimiters = new string[] { " " };
    parser.HasFieldsEnclosedInQuotes = true; // <--- !!!
    string[] lineFields;
    while ((lineFields = parser.ReadFields()) != null)
    {
        allLineFields.Add(lineFields);
    }
}

对于您的示例字符串,列表包含一个带有四个令牌的string[]

-p
This is a string "with quotes"
d:'1.txt
d:'some folder'1.out

使用正则表达式(如果你坚持不使用Tim Schmelter的答案所建议的解析器),这样的东西应该可以工作(它匹配给定的字符串,但我不能保证它是完全防弹的):

((?:"(?:[^"]|"")*")|'S+)

分解后,您将分组:

  • 一个引号",后面不是引号^",或者两个引号"",后面是引号"
  • 一组(一个或多个)非空格字符'S

请参阅此处玩它。

手写版本:

private static string[] ParseArguments(string text)
{
    if (string.IsNullOrWhiteSpace(text)) return new string[0];
    var entries = new List<string>(8);
    var stringBuilder = new StringBuilder(64);
    var inString  = false;
    var l = text.Length;
    for (var i = 0; i < l; i++)
    {
        var c = text[i];
        if (inString)
        {
            if (c == '"')
            {
                if (i != l - 1 && text[i + 1] == '"')
                {
                    stringBuilder.Append(c);
                    i++;
                }
                else inString = false;
            }
            else stringBuilder.Append(c);
        }
        else if (c == '"') inString = true;
        else if (char.IsWhiteSpace(c))
        {
            if (stringBuilder.Length == 0) continue;
            entries.Add(stringBuilder.ToString());
            stringBuilder.Length = 0;
        }
        else stringBuilder.Append(c);
    }
    if (stringBuilder.Length != 0) entries.Add(stringBuilder.ToString());
    return entries.ToArray();
}