【问题标题】:c# comma separated string to listc#逗号分隔的字符串列表
【发布时间】:2017-01-01 04:07:21
【问题描述】:

我已经看到一堆使用 Split(',') 处理逗号分隔列表的示例,例如:

string csv = "1,2,3,4,a,5";
List<string> parts = csv.Split(',').ToList<string>();

但是会发生什么,你将如何处理这样的 CSV 字符串:

string csv = '"a,b","c,d","e","f",g,h,i';

我希望能够将 csv 字符串解析为列表或数组,更多的是了解处理其中包含逗号的字符串元素的最佳方法,而不是像 Split 这样的简单解析器对多余的逗号感到困惑。

Alexei 的评论很有帮助,但在我的现实生活示例中尝试过之后,他的解决方案遇到了一些障碍。所以为了额外的功劳。这是一个更准确的 csv 字符串,需要解析。

csv = '"name 1" <title 1>, "name, 2" <title 2>, name 3 <title 3>, name 4 <title 4>, name 5, name 6';

这些值将被分成:

"name 1" <title 1>
"name, 2" <title 2> 
name 3 <title 3>
name 4 <title 4> 
name 5
name 6

谢谢

【问题讨论】:

  • 在 NuGet 上查找 CSV 解析器。
  • 试试 CSVHelper:joshclose.github.io/CsvHelper
  • 第二个字符串的输出期望是什么?
  • 默认情况下,使用 Split 解析 CSV 的所有答案都是错误的,但由于某种原因,它们充满了它们:[

标签: c# arrays string list csv


【解决方案1】:

使用正则表达式来做到这一点。这是最快和最简单的方法。确保将System.Text.RegularExpressions 添加到您的参考文献中。将单引号和双引号作为您的特殊字符,它将把它们去掉。有关详细信息,请参阅此帖子。

Regex remove special characters

【讨论】:

  • 正则表达式对此很糟糕。相对于专用解析器而言,它的速度很慢,并且仍然容易受到许多边缘情况的影响。从 Nuget 添加一个真正的 csv 解析器非常容易,或者如果您不喜欢依赖项,您可以找到许多单个 *.cs 文件选项并将其包含在您的项目中。
  • 恕我直言@Joel Coehoorn 通常有不止一种给猫剥皮的方法。我不会说正则表达式很糟糕,它取决于要求和应用程序,这取决于操作员来决定。我们的工作是展示可能性,而正则表达式无疑是一种可行的解决方案。虽然它可能会对性能产生影响,但这种影响可以忽略不计,同样取决于操作的应用程序。它也有一些利大于弊的优点。
  • 为了帮助运维,这里有一篇文章。 blogs.msdn.microsoft.com/oanapl/2009/04/04/…我不会说我的方式是最好的方式,它只是另一种方式。阅读文章并试用它们,看看什么最适合您和您的应用程序。正则表达式可能会影响性能,但它可能很小,不会影响您
  • 引号不是特殊字符,它们是单元格包含分隔符时使用的文本分隔符。虽然正则表达式可用于解析 CSV,但此答案只会破坏数据
  • 在我的真实数据集中我发现我只需要([^&gt;]+&gt;)[, ]{0,2} 之前RegEx中的其他两个选项解决了上面的扩展示例。
【解决方案2】:

第二个字符串的普通 C# 解决方案。它假定它是一个有效的 CSV,令牌之间没有空格。我认为它不是最快的,但对于合理大小的数组 (~MB) 来说应该足够了。复杂度是O(n):

private static void AddToBuilder(IList<string> parts, StringBuilder sb)
{
    if (sb.Length > 0)
        parts.Add(sb.ToString());

    sb.Clear();
}

static void Main(string[] args)
{
    string csv = "\"a,b\",\"c,d\",\"e\",\"f\",g,h,i";
    var parts = new List<string>();
    bool innerString = false;
    var sb = new StringBuilder();
    foreach (var c in csv)
    {
        if (c == '\"')
        {
            if (innerString)
                AddToBuilder(parts, sb);

            innerString = !innerString;
            continue;
        }

        if (c == ',' && !innerString)
        {
            AddToBuilder(parts, sb);
            continue;
        }

        sb.Append(c);
    }

    AddToBuilder(parts, sb);

【讨论】:

    【解决方案3】:

    如果无法选择第三方 CSV 解析器,另一种选择是 Microsoft.VisualBasic.FileIO.TextFieldParser(需要参考 Microsoft.VisualBasic):

    string CSV = "\"a,b\",\"c,d\",\"e\",\"f\",g,h,i";
    string[] fields;
    
    using (var sr = new System.IO.StringReader(CSV))  
    using (var tfp = new Microsoft.VisualBasic.FileIO.TextFieldParser(sr)) {
        tfp.SetDelimiters(",");
        fields = tfp.ReadFields();
    }
    

    它还处理包含正确转义引号的值。

    【讨论】:

    • 好建议,您需要添加 References -> Assemblies -> Framework -> Microsoft.VisualBasic 以使其适用于 C#。不幸的是,它无法在我的数据集上解决我的问题,但可能对其他人有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-22
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多