使用C#中的复杂性解析逗号分隔字符串

时间:2015-05-06 13:21:27

标签: c# string list parsing substring

我知道如何从一个字符串中获取子字符串,这些字符串是昏迷分离的,但这里有一个复杂因素:如果substring包含昏迷,该怎么办。

如果子字符串包含逗号,新行或双引号,则整个子字符串将用双引号封装。

如果子字符串包含双引号,则双引号将使用另一个双引号进行转义。 最糟糕的情况是,如果我有这样的事情:

first,"second, second","""third"" third","""fourth"", fourth"

在这种情况下,子串是:

  • 第一
  • 第二,第二
  • “第三”第三
  • “第四”,第四次

第二个,第二个用双引号封装,我不希望列表/数组中的那些双引号。

“third”第三个用双引号封装,因为它包含双引号,并且使用aditional双引号进行转义。我再次不希望在列表/数组中封装双引号,我不希望双引号转义为双引号,但我想要原始双引号,它是子字符串的一部分。

6 个答案:

答案 0 :(得分:4)

使用TextFieldParser的一种方式:

using (var reader = new StringReader("first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\""))    
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader))
{
    parser.Delimiters = new[] { "," };
    parser.HasFieldsEnclosedInQuotes = true;

    while (!parser.EndOfData)
    {
        foreach (var field in parser.ReadFields())
            Console.WriteLine(field);
    }
}

有关

first
second, second
"third" third
"fourth", fourth

答案 1 :(得分:0)

试试这个



           string input = "first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\"";

            string[] output = input.Split(new string[] {"\",\""}, StringSplitOptions.RemoveEmptyEntries);




答案 2 :(得分:0)

我建议你为这个问题构建一个小型状态机。你会有像:

这样的州
  • Out - 在到达第一个字段之前
  • InQuoted - 你出去了,“到了;现在你进去了,而且这个领域被引用
  • InQuotedMaybeOut - 你是InQuoted并且“到了;现在你等待下一个角色来判断它是否是另一个”或其他东西; if else,然后选择下一个有效状态(字符可以是空格,换行,逗号,所以你决定下一个状态);否则,如果“到达,你推”到输出并退回到InQuoted
  • In-after-out,当任何角色到达时,除了和,“你自动进入一个没有引用的新领域。

这肯定会正确读取CSV。您还可以使分隔符可配置,以便支持TSV或以分号分隔的格式。

另请注意CSV格式中一个非常重要的情况:引用字段可能包含新行!另一个值得注意的特殊情况:空场(如:,,)。

答案 3 :(得分:0)

这不是最优雅的解决方案,但它可能对您有所帮助。我会遍历字符并对引号进行奇数计数。例如,如果您遇到奇数引号则为true,对于偶数引号则为false。

当此bool值为true时遇到的任何逗号都不应被视为分隔符。如果您知道它是一个分隔符,您可以使用该信息执行多项操作。下面我用更易于管理的东西替换了分隔符(虽然效率不高):

bool odd = false;
char replacementDelimiter = "|"; // Or some very unlikely character

for(int i = 0; i < str.len; ++i)
{
   if(str[i] == '\"')
       odd = !odd;
   else if (str[i] == ',')
   {
      if(!odd)
          str[i] = replacementDelimiter;
   }
}

string[] commaSeparatedTokens = str.Split(replacementDelimiter);

此时你应该有一个字符串数组,这些字符串在你想要的逗号上分开。从这里开始,处理报价会更简单。

我希望这可以帮到你。

答案 4 :(得分:0)

迷你解析器

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp
{
    class Program
    {
        private static IEnumerable<string> Parse(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                // empty string => nothing to do
                yield break;
            }

            int count = input.Length;
            StringBuilder sb = new StringBuilder();
            int j;

            for (int i = 0; i < count; i++)
            {
                char c = input[i];
                if (c == ',')
                {
                    yield return sb.ToString();
                    sb.Clear();
                }
                else if (c == '"')
                {
                    // begin quoted string
                    sb.Clear();
                    for (j = i + 1; j < count; j++)
                    {
                        if (input[j] == '"')
                        {
                            // quote
                            if (j < count - 1 && input[j + 1] == '"')
                            {
                                // double quote
                                sb.Append('"');
                                j++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            sb.Append(input[j]);
                        }
                    }
                    yield return sb.ToString();

                    // clear buffer and skip to next comma
                    sb.Clear();
                    for (i = j + 1; i < count && input[i] != ','; i++) ;
                }
                else
                {
                    sb.Append(c);
                }
            }
        }

        [STAThread]
        static void Main(string[] args)
        {
            foreach (string str in Parse("first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\""))
            {
                Console.WriteLine(str);
            }

            Console.WriteLine();
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}

结果

  • 第一
  • 第二,第二
  • &#34;第三&#34;第三
  • &#34;第四&#34;,第四

答案 5 :(得分:0)

感谢您的回答,但在我看到它们之前,我写了这个解决方案,它并不漂亮,但它对我有用。

string line = "first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\"";
var substringArray = new List<string>();
string substring = null;
var doubleQuotesCount = 0;

for (var i = 0; i < line.Length; i++)
{
  if (line[i] == ',' && (doubleQuotesCount % 2) == 0)
  {
    substringArray.Add(substring);
    substring = null;
    doubleQuotesCount = 0;
    continue;
  }
  else
  {
    if (line[i] == '"')
      doubleQuotesCount++;

    substring += line[i];

    //If it is a last character
    if (i == line.Length - 1)
    {
      substringArray.Add(substring);
      substring = null;
      doubleQuotesCount = 0;
    }
  }
}

for(var i = 0; i < substringArray.Count; i++)
{
  if (substringArray[i] != null)
  {
    //remove first double quote
    if (substringArray[i][0] == '"')
    {
      substringArray[i] = substringArray[i].Substring(1);
    }
    //remove last double quote
    if (substringArray[i][substringArray[i].Length - 1] == '"')
    {
      substringArray[i] = substringArray[i].Remove(substringArray[i].Length - 1);
    }
    //Replace double double quotes with single double quote
    substringArray[i] = substringArray[i].Replace("\"\"", "\"");
  }
}