C# 解析C中带引号的CSV文件#

C# 解析C中带引号的CSV文件#,c#,csv,C#,Csv,我在解析CSV文件中看到了很多示例。但是这个文件有点烦人 那么如何解析这种CSV呢 “1”,2010年1月2日,“样本(“adasdad”)asdada”,“我在门上大便“臭”,所以我会该死”,“AK”基于 “ 我会使用MyString.IndexOf(“\”,” 然后再对部分进行子串。除此之外,我确信有人编写了一个csv解析器,可以处理此问题:)您可以将字符串拆分为,“”。建议csv文件中的每一个单元格值都应该用引号括起来,如“1”、“2”、“3”…如果每一行都不一样,我看不出有什么办法。这一

我在解析CSV文件中看到了很多示例。但是这个文件有点烦人

那么如何解析这种CSV呢

“1”,2010年1月2日,“样本(“adasdad”)asdada”,“我在门上大便“臭”,所以我会该死”,“AK”

基于

我会使用MyString.IndexOf(“\”,”


然后再对部分进行子串。除此之外,我确信有人编写了一个csv解析器,可以处理此问题:)

您可以将字符串拆分为
,“
”。建议csv文件中的每一个单元格值都应该用引号括起来,如“1”、“2”、“3”…

如果每一行都不一样,我看不出有什么办法。这一行的CSV格式不正确。值中包含的引号必须加倍,如下所示。我甚至不能确定这些值应该在哪里终止

"1",1/2/2010,"The sample (""adasdad"") asdada","I was pooping in the door ""Stinky"", so I'll be damn","AK"
但我不知道任何代码如何处理您的行,因为它的格式不正确。

您可能想试试。它可以很好地处理带引号的字符串,所以您只需删除前导引号和尾随引号


如果您的字符串包含一个coma,则它将失败。为了避免这种情况,引用需要像其他答案中所说的那样加倍。

我强烈建议使用。使用
String.Split
或正则表达式的手工编码解析器几乎总是错误地处理带有嵌入引号或分隔符的引用字段

不过,如果它处理了您的特定示例,我会感到惊讶。正如其他人所说,这一行充其量是模棱两可的。

作为否(得体)。csv解析器可以正确解析非csv数据,任务不是解析数据,而是修复文件(然后解析正确的数据)

要修复数据,您需要一个坏行列表(发送给垃圾负责人进行手动编辑)。要获得这样的列表,您可以

  • 使用具有正确导入规范的Access导入文件。您将获得导入失败的列表

  • 编写通过OLEDB文本驱动程序打开文件的脚本/程序

  • 示例文件:

    "Id","Remark","DateDue"
    1,"This is good",20110413
    2,"This is ""good""",20110414
    3,"This is ""good"","bad",and "ugly",,20110415
    4,"This is ""good""" again,20110415
    
    示例SQL/结果:

     SELECT * FROM [badcsv01.csv]
     Id Remark               DateDue   
      1 This is good         4/13/2011 
      2 This is "good"       4/14/2011 
      3 This is "good",        NULL    
      4 This is "good" again 4/15/2011 
    
    SELECT * FROM [badcsv01.csv] WHERE DateDue Is Null
     Id Remark          DateDue 
      3 This is "good",  NULL   
    

    我找到了一种解析这个格式错误的CSV的方法。我寻找了一个模式,发现了它。。。。我首先将(“,”)替换为一个字符。。。像“·”然后把它分开

    由此:

    "Annoying","CSV File","poop@mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby","yeah!"
    
    为此:

    "Annoying¤CSV File¤poop@mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby¤yeah!"
    
    然后将其拆分:

    ArrayA[0]: "Annoying //this value will be trimmed by replace("\"","") same as the array[4]
    ArrayA[1]: CSV File
    ArrayA[2]: poop@mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby
    ArrayA[3]: yeah!"
    
    拆分后,我会将ArrayA[2]“和”中的字符串替换为·,然后再次拆分

    由此

    ArrayA[2]: poop@mypants.com",1999,01-20-2001,"oh,boy",01-20-2001,"yeah baby
    
    对此

    ArrayA[2]: poop@mypants.com¤1999,01-20-2001¤oh,boy¤01-20-2001¤yeah baby
    
    然后再把它分开,然后转向这个

    ArrayB[0]: poop@mypants.com
    ArrayB[1]: 1999,01-20-2001
    ArrayB[2]: oh,boy
    ArrayB[3]: 01-20-2001
    ArrayB[4]: yeah baby
    
    最后。。。我将仅将年份和日期从ArrayB[1]与,拆分为ArrayC


    这很乏味,但没有其他方法可以做到…

    在大多数情况下,最好的答案可能是@Jim Mischel's
    TextFieldParser
    似乎正是大多数常规情况下所需要的——尽管奇怪的是,但这种情况并不常规。

    上次我在这个问题上遇到了一个变体,我需要一些非常规的东西,我尴尬地放弃了regexp'ing,并固执地进行逐字符检查。有时候,这还不够错误。如果按字节,拆分字符串并不是那么困难的问题

    所以我重写了这个案例作为字符串扩展。我想这很接近

    请注意,
    “我在门上大便“臭”,所以我会被诅咒,
    是一个特别恶劣的案例。如果没有
    ***臭烘烘的条件***
    代码,下面,你会得到
    我在门上大便的“臭烘烘的”
    作为一个值,而
    因此我会像另一个值一样该死“

    唯一比任何匿名怪异拆分器/转义器更好的方法是使用某种算法来确定每行中“通常”的列数,然后检查,在这种情况下,固定长度字段,如
    AK
    状态条目或其他一些可能的地标,作为非一致列的一种规范化支持。但这是一种很严重的疯狂逻辑,可能并不需要,因为编写代码会很有趣。正如@Vash所指出的,您最好遵循一些标准,编写更具攻击性的代码

    但这里的问题可能比这更简单唯一在词汇上有意义的案例是您的示例中的案例--”,--双引号,逗号,然后是空格。所以这就是
    ***臭烘烘的条件***
    代码检查的内容。即使如此,这段代码比我想要的更糟糕,这意味着您有过奇怪的边缘案例,比如
    “这也是臭烘烘的,“a、f、a、b”、“现在怎么办?”
    Heck,甚至
    “a、b”、“C”
    现在在这个代码中都不起作用,iirc,因为我把开始和结束字符视为已在转义前和后修复。所以我们基本上回到@Vash的评论上来了

    为一行
    if
    语句的所有括号表示歉意,但我现在陷入了一个StyleCop世界。我不一定建议你使用这个-
    StrightscapeToSpliteValuation
    再加上臭气熏天的条件使得这个有点复杂。但是值得记住的是,一个关于引号的智能化的普通csv解析器要简单得多,虽然繁琐,但在其他方面却微不足道

    namespace YourFavoriteNamespace 
    {
        using System;
        using System.Collections.Generic;
        using System.Text;
    
        public static class Extensions
        {
            public static Queue<string> SplitSeeingQuotes(this string valToSplit, char splittingChar = ',', char escapeChar = '"', 
                bool strictEscapeToSplitEvaluation = true, bool captureEndingNull = false)
            {
                Queue<string> qReturn = new Queue<string>();
                StringBuilder stringBuilder = new StringBuilder();
    
                bool bInEscapeVal = false;
    
                for (int i = 0; i < valToSplit.Length; i++)
                {
                    if (!bInEscapeVal)
                    {
                        // Escape values must come immediately after a split.
                        // abc,"b,ca",cab has an escaped comma.
                        // abc,b"ca,c"ab does not.
                        if (escapeChar == valToSplit[i] && (!strictEscapeToSplitEvaluation || (i == 0 || (i != 0 && splittingChar == valToSplit[i - 1]))))
                        {
                            bInEscapeVal = true;    // not capturing escapeChar as part of value; easy enough to change if need be.
                        }
                        else if (splittingChar == valToSplit[i])
                        {
                            qReturn.Enqueue(stringBuilder.ToString());
                            stringBuilder = new StringBuilder();
                        }
                        else
                        {
                            stringBuilder.Append(valToSplit[i]);
                        }
                    }
                    else
                    {
                        // Can't use switch b/c we're comparing to a variable, I believe.
                        if (escapeChar == valToSplit[i])
                        {
                            // Repeated escape always reduces to one escape char in this logic.
                            // So if you wanted "I'm ""double quote"" crazy!" to come out with 
                            // the double double quotes, you're toast.
                            if (i + 1 < valToSplit.Length && escapeChar == valToSplit[i + 1])
                            {
                                i++;
                                stringBuilder.Append(escapeChar);
                            }
                            else if (!strictEscapeToSplitEvaluation)
                            {
                                bInEscapeVal = false;
                            }
                            // *** STINKY CONDITION ***  
                            // Kinda defense, since only `", ` really makes sense.
                            else if ('"' == escapeChar && i + 2 < valToSplit.Length &&
                                valToSplit[i + 1] == ',' && valToSplit[i + 2] == ' ')
                            {
                                i = i+2;
                                stringBuilder.Append("\", ");
                            }
                            // *** EO STINKY CONDITION ***  
                            else if (i+1 == valToSplit.Length || (i + 1 < valToSplit.Length && valToSplit[i + 1] == splittingChar))
                            {
                                bInEscapeVal = false;
                            }
                            else
                            {
                                stringBuilder.Append(escapeChar);
                            }
                        }
                        else
                        {
                            stringBuilder.Append(valToSplit[i]);
                        }
                    }
                }
    
                // NOTE: The `captureEndingNull` flag is not tested.
                // Catch null final entry?  "abc,cab,bca," could be four entries, with the last an empty string.
                if ((captureEndingNull && splittingChar == valToSplit[valToSplit.Length-1]) || (stringBuilder.Length > 0))
                {
                    qReturn.Enqueue(stringBuilder.ToString());
                }
    
                return qReturn;
            }
        }
    }
    
    名称空间YourFavoriteMespace
    {
    使用制度;
    使用System.Collections.Generic;
    使用系统文本;
    公共静态类扩展
    {
    公共静态队列拆分SeeingQuotes(此字符串为valToSplit,char splittingChar=',',char escapeChar='”,
    bool StritescapeToSpliteValuation=true,bool captureEndingNull=false)
    {
    Queue qReturn=新队列();
    StringBuilder StringBuilder=新的StringBuilder();
    bool bInEscapeVal=false;
    for(int i=0;i            DataTable pbResults = new DataTable();
                OracleDataAdapter oda = new OracleDataAdapter(cmd);
                oda.Fill(pbResults);
    
                StringBuilder sb1 = new StringBuilder();
                StringBuilder sb2 = new StringBuilder();
                IEnumerable<string> columnNames = pbResults.Columns.Cast<DataColumn>().Select(column => column.ColumnName);
    
                sb1.Append(string.Join("\"" + "," + "\"", columnNames));                
                sb2.Append("\"");
                sb2.Append(sb1);
                sb2.AppendLine("\"");
    
                foreach (DataRow row in pbResults.Rows)
                {
                    IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString());
                    sb2.Append("\"");
                    sb2.Append(string.Join("\"" + "," + "\"", fields));
                    sb2.AppendLine("\"");
                }
    
    string csv = @"""1"",1/2/2010,""The sample(""adasdad"") asdada"",""I was pooping in the door ""Stinky"", so I'll be damn"",""AK""";
    
    using (var r = ChoCSVReader.LoadText(csv)
        .QuoteAllFields()
        )
    {
        foreach (var rec in r)
            Console.WriteLine(rec.Dump());
    }
    
    [Count: 5]
    Key: Column1 [Type: Int64]
    Value: 1
    Key: Column2 [Type: DateTime]
    Value: 1/2/2010 12:00:00 AM
    Key: Column3 [Type: String]
    Value: The sample(adasdad) asdada
    Key: Column4 [Type: String]
    Value: I was pooping in the door Stinky, so I'll be damn
    Key: Column5 [Type: String]
    Value: AK