我以为这很琐碎,但我无法解决这个问题。

假设CSV文件中有一行:"Barack Obama", 48, "President", "1600 Penn Ave, Washington DC"string[] tokens = line.split(',')
我期望这样:

 "Barack Obama"
 48
 "President"
 "1600 Penn Ave, Washington DC"

但是最后一个记号是
'Washington DC'不是
"1600 Penn Ave, Washington DC"

是否有一种简单的方法来使split函数忽略引号内的逗号?

我无法控制CSV文件,也无法将其发送给我。客户A将使用该应用程序读取外部人员提供的文件。

最佳答案

您可能必须编写自己的split函数。

  • 遍历字符串
  • 中的每个字符
  • 当您按下"字符时,切换一个 bool
  • 当您打逗号时,如果 bool 值是正确的,请忽略它,否则,您将获得 token

  • 这是一个例子:
    public static class StringExtensions
    {
        public static string[] SplitQuoted(this string input, char separator, char quotechar)
        {
            List<string> tokens = new List<string>();
    
            StringBuilder sb = new StringBuilder();
            bool escaped = false;
            foreach (char c in input)
            {
                if (c.Equals(separator) && !escaped)
                {
                    // we have a token
                    tokens.Add(sb.ToString().Trim());
                    sb.Clear();
                }
                else if (c.Equals(separator) && escaped)
                {
                    // ignore but add to string
                    sb.Append(c);
                }
                else if (c.Equals(quotechar))
                {
                    escaped = !escaped;
                    sb.Append(c);
                }
                else
                {
                    sb.Append(c);
                }
            }
            tokens.Add(sb.ToString().Trim());
    
            return tokens.ToArray();
        }
    }
    

    然后只需致电:
    string[] tokens = line.SplitQuoted(',','\"');
    

    基准测试

    对我的代码和Dan Tao的代码进行基准测试的结果如下。如果有人需要,我很乐意为其他解决方案提供基准?

    代码:
    string input = "\"Barak Obama\", 48, \"President\", \"1600 Penn Ave, Washington DC\""; // Console.ReadLine()
    string[] tokens = null;
    
    // run tests
    DateTime start = DateTime.Now;
    for (int i = 0; i < 1000000; i++)
        tokens = input.SplitWithQualifier(',', '\"', false);
    Console.WriteLine("1,000,000 x SplitWithQualifier = {0}ms", DateTime.Now.Subtract(start).TotalMilliseconds);
    
    start = DateTime.Now;
    for (int i = 0; i<1000000;i++)
        tokens = input.SplitQuoted(',', '\"');
    Console.WriteLine("1,000,000 x SplitQuoted =        {0}ms", DateTime.Now.Subtract(start).TotalMilliseconds);
    

    输出:
    1,000,000 x SplitWithQualifier = 8156.25ms
    1,000,000 x SplitQuoted =        2406.25ms
    

    09-26 22:36