it-swarm.com.de

teilen Sie eine durch Kommas getrennte Zeichenfolge sowohl in Anführungszeichen als auch in Anführungszeichen auf

Ich habe die folgende durch Kommas getrennte Zeichenfolge, die ich teilen muss. Das Problem ist, dass ein Teil des Inhalts in Anführungszeichen steht und Kommas enthält, die nicht in der Aufteilung verwendet werden sollten.

String:

111,222,"33,44,55",666,"77,88","99"

Ich möchte die Ausgabe:

111  
222  
33,44,55  
666  
77,88  
99  

Ich habe das ausprobiert: 

(?:,?)((?<=")[^"]+(?=")|[^",]+)   

Es liest jedoch das Komma zwischen "77,88", "99" als Treffer und ich erhalte folgende Ausgabe: 

111  
222  
33,44,55  
666  
77,88  
,  
99  

Kann mir jemand helfen? Ich habe keine Stunden mehr ...:) /Peter

44
Peter Norlén

Abhängig von Ihren Bedürfnissen können Sie möglicherweise keinen CSV-Parser verwenden und möchten das Rad tatsächlich neu erfinden !!

Sie können dies mit einer einfachen Regex tun

(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)

Dies wird Folgendes tun:

(?:^|,) = Übereinstimmungsausdruck "Zeilenanfang oder Zeichenkette ,"

(\"(?:[^\"]+|\"\")*\"|[^,]*) = Eine nummerierte Erfassungsgruppe. Hier können Sie zwischen zwei Alternativen wählen:

  1. zeug in Anführungszeichen
  2. zeug zwischen Kommas

Dies sollte Ihnen die Ausgabe liefern, nach der Sie suchen.

Beispielcode in C #

 static Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);

public static string[] SplitCSV(string input)
{

  List<string> list = new List<string>();
  string curr = null;
  foreach (Match match in csvSplit.Matches(input))
  {        
    curr = match.Value;
    if (0 == curr.Length)
    {
      list.Add("");
    }

    list.Add(curr.TrimStart(','));
  }

  return list.ToArray();
}

private void button1_Click(object sender, RoutedEventArgs e)
{
    Console.WriteLine(SplitCSV("111,222,\"33,44,55\",666,\"77,88\",\"99\""));
}

Warning Wie in @ MrEs Kommentar - Wenn in einer schlecht formatierten CSV-Datei ein böses neues Zeilenzeichen erscheint und Sie eine ungerade Zahl ("Zeichenfolge") erhalten, werden Sie katastrophale Rückverfolgung ( https: // www. regular-expressions.info/catastrophic.html ) in Ihrem Regex und Ihr System wird wahrscheinlich abstürzen (wie bei unserem Produktionssystem). Kann leicht in Visual Studio repliziert werden und ich habe festgestellt, dass es abstürzt. Ein einfacher Versuch/catch wird dieses Problem auch nicht einfangen.

Du solltest benutzen:

(?:^|,)(\"(?:[^\"])*\"|[^,]*)

stattdessen

79
jimplode

ich mag wirklich die Antwort von jimplode, aber ich denke, eine Version mit Renditeertrag ist ein bisschen nützlicher, daher hier:

public IEnumerable<string> SplitCSV(string input)
{
    Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);

    foreach (Match match in csvSplit.Matches(input))
    {
        yield return match.Value.TrimStart(',');
    }
}

Vielleicht ist es sogar sinnvoller, es als Erweiterungsmethode zu haben:

public static class StringHelper
{
    public static IEnumerable<string> SplitCSV(this string input)
    {
        Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);

        foreach (Match match in csvSplit.Matches(input))
        {
            yield return match.Value.TrimStart(',');
        }
    }
}
13
qqbenq

Dieser reguläre Ausdruck funktioniert ohne die Notwendigkeit, Werte und TrimStart(',') wie in der akzeptierten Antwort durchlaufen zu müssen:

((?<=\")[^\"]*(?=\"(,|$)+)|(?<=,|^)[^,\"]*(?=,|$))

Hier ist die Implementierung in C #:

string values = "111,222,\"33,44,55\",666,\"77,88\",\"99\"";

MatchCollection matches = new Regex("((?<=\")[^\"]*(?=\"(,|$)+)|(?<=,|^)[^,\"]*(?=,|$))").Matches(values);

foreach (var match in matches)
{
    Console.WriteLine(match);
}

Ausgänge

111  
222  
33,44,55  
666  
77,88  
99  
4

Keine dieser Antworten funktioniert, wenn der String in Anführungszeichen ein Komma enthält, wie in "value, 1", oder in doppelte Anführungszeichen, wie in "value ""1""". Dies sind gültige CSV , die als value, 1 bzw. value "1" analysiert werden sollten.

Dies funktioniert auch mit dem durch Tabulatoren getrennten Format, wenn Sie ein Tab anstatt eines Kommas als Trennzeichen übergeben.

public static IEnumerable<string> SplitRow(string row, char delimiter = ',')
{
    var currentString = new StringBuilder();
    var inQuotes = false;
    var quoteIsEscaped = false; //Store when a quote has been escaped.
    row = string.Format("{0}{1}", row, delimiter); //We add new cells at the delimiter, so append one for the parser.
    foreach (var character in row.Select((val, index) => new {val, index}))
    {
        if (character.val == delimiter) //We hit a delimiter character...
        {
            if (!inQuotes) //Are we inside quotes? If not, we've hit the end of a cell value.
            {
                Console.WriteLine(currentString);
                yield return currentString.ToString();
                currentString.Clear();
            }
            else
            {
                currentString.Append(character.val);
            }
        } else {
            if (character.val != ' ')
            {
                if(character.val == '"') //If we've hit a quote character...
                {
                    if(character.val == '\"' && inQuotes) //Does it appear to be a closing quote?
                    {
                        if (row[character.index + 1] == character.val) //If the character afterwards is also a quote, this is to escape that (not a closing quote).
                        {
                            quoteIsEscaped = true; //Flag that we are escaped for the next character. Don't add the escaping quote.
                        }
                        else if (quoteIsEscaped)
                        {
                            quoteIsEscaped = false; //This is an escaped quote. Add it and revert quoteIsEscaped to false.
                            currentString.Append(character.val);
                        }
                        else
                        {
                            inQuotes = false;
                        }
                    }
                    else
                    {
                        if (!inQuotes)
                        {
                            inQuotes = true;
                        }
                        else
                        {
                            currentString.Append(character.val); //...It's a quote inside a quote.
                        }
                    }
                }
                else
                {
                    currentString.Append(character.val);
                }
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(currentString.ToString())) //Append only if not new cell
                {
                    currentString.Append(character.val);
                }
            }
        }
    }
}
3
Chad Hedgcock

Schnell und einfach:

    public static string[] SplitCsv(string line)
    {
        List<string> result = new List<string>();
        StringBuilder currentStr = new StringBuilder("");
        bool inQuotes = false;
        for (int i = 0; i < line.Length; i++) // For each character
        {
            if (line[i] == '\"') // Quotes are closing or opening
                inQuotes = !inQuotes;
            else if (line[i] == ',') // Comma
            {
                if (!inQuotes) // If not in quotes, end of current string, add it to result
                {
                    result.Add(currentStr.ToString());
                    currentStr.Clear();
                }
                else
                    currentStr.Append(line[i]); // If in quotes, just add it 
            }
            else // Add any other character to current string
                currentStr.Append(line[i]); 
        }
        result.Add(currentStr.ToString());
        return result.ToArray(); // Return array of all strings
    }

Mit dieser Zeichenfolge als Eingabe:

 111,222,"33,44,55",666,"77,88","99"

Es wird zurückkehren:

111  
222  
33,44,55  
666  
77,88  
99  
3
Antoine

Mit geringfügigen Updates der Funktion von "Chad Hedgcock".

Updates sind am: 

Zeile 26: character.val == '\ "' - Dies kann aufgrund der in Zeile 24 durchgeführten Überprüfung niemals wahr sein. D. H. Character.val == '' '

Zeile 28: Wenn (Zeile [character.index + 1] == character.val)! QuoteIsEscaped hinzugefügt, um 3 aufeinanderfolgende Anführungszeichen zu vermeiden.

public static IEnumerable<string> SplitRow(string row, char delimiter = ',')
{
var currentString = new StringBuilder();
var inQuotes = false;
var quoteIsEscaped = false; //Store when a quote has been escaped.
row = string.Format("{0}{1}", row, delimiter); //We add new cells at the delimiter, so append one for the parser.
foreach (var character in row.Select((val, index) => new {val, index}))
{
    if (character.val == delimiter) //We hit a delimiter character...
    {
        if (!inQuotes) //Are we inside quotes? If not, we've hit the end of a cell value.
        {
            //Console.WriteLine(currentString);
            yield return currentString.ToString();
            currentString.Clear();
        }
        else
        {
            currentString.Append(character.val);
        }
    } else {
        if (character.val != ' ')
        {
            if(character.val == '"') //If we've hit a quote character...
            {
                if(character.val == '"' && inQuotes) //Does it appear to be a closing quote?
                {
                    if (row[character.index + 1] == character.val && !quoteIsEscaped) //If the character afterwards is also a quote, this is to escape that (not a closing quote).
                    {
                        quoteIsEscaped = true; //Flag that we are escaped for the next character. Don't add the escaping quote.
                    }
                    else if (quoteIsEscaped)
                    {
                        quoteIsEscaped = false; //This is an escaped quote. Add it and revert quoteIsEscaped to false.
                        currentString.Append(character.val);
                    }
                    else
                    {
                        inQuotes = false;
                    }
                }
                else
                {
                    if (!inQuotes)
                    {
                        inQuotes = true;
                    }
                    else
                    {
                        currentString.Append(character.val); //...It's a quote inside a quote.
                    }
                }
            }
            else
            {
                currentString.Append(character.val);
            }
        }
        else
        {
            if (!string.IsNullOrWhiteSpace(currentString.ToString())) //Append only if not new cell
            {
                currentString.Append(character.val);
            }
        }
    }
}

}

3
Shiva

Für Jays Antwort können Sie, wenn Sie einen zweiten Booleschen Befehl verwenden, doppelte Anführungszeichen in Anführungszeichen setzen und umgekehrt.

    private string[] splitString(string stringToSplit)
{
    char[] characters = stringToSplit.ToCharArray();
    List<string> returnValueList = new List<string>();
    string tempString = "";
    bool blockUntilEndQuote = false;
    bool blockUntilEndQuote2 = false;
    int characterCount = 0;
    foreach (char character in characters)
    {
        characterCount = characterCount + 1;

        if (character == '"' && !blockUntilEndQuote2)
        {
            if (blockUntilEndQuote == false)
            {
                blockUntilEndQuote = true;
            }
            else if (blockUntilEndQuote == true)
            {
                blockUntilEndQuote = false;
            }
        }
        if (character == '\'' && !blockUntilEndQuote)
        {
            if (blockUntilEndQuote2 == false)
            {
                blockUntilEndQuote2 = true;
            }
            else if (blockUntilEndQuote2 == true)
            {
                blockUntilEndQuote2 = false;
            }
        }

        if (character != ',')
        {
            tempString = tempString + character;
        }
        else if (character == ',' && (blockUntilEndQuote == true || blockUntilEndQuote2 == true))
        {
            tempString = tempString + character;
        }
        else
        {
            returnValueList.Add(tempString);
            tempString = "";
        }

        if (characterCount == characters.Length)
        {
            returnValueList.Add(tempString);
            tempString = "";
        }
    }

    string[] returnValue = returnValueList.ToArray();
    return returnValue;
}
2
And Wan

Erneuere nicht einen CSV-Parser, versuche FileHelpers .

2
Darin Dimitrov

Versuche dies:

       string s = @"111,222,""33,44,55"",666,""77,88"",""99""";

       List<string> result = new List<string>();

       var splitted = s.Split('"').ToList<string>();
       splitted.RemoveAll(x => x == ",");
       foreach (var it in splitted)
       {
           if (it.StartsWith(",") || it.EndsWith(","))
           {
               var tmp = it.TrimEnd(',').TrimStart(',');
               result.AddRange(tmp.Split(','));
           }
           else
           {
               if(!string.IsNullOrEmpty(it)) result.Add(it);
           }
      }
       //Results:

       foreach (var it in result)
       {
           Console.WriteLine(it);
       }
2
nan

Ich brauchte etwas robusteres, also habe ich von hier genommen und dieses erstellt ... Diese Lösung ist etwas weniger elegant und ein wenig ausführlicher, aber bei meinen Tests (mit einem 1.000.000-Zeilen-Sample) fand ich, dass dies 2 war bis 3 mal schneller. Außerdem werden nicht eingebettete Anführungszeichen ohne Escapezeichen verarbeitet. Ich habe aufgrund der Anforderungen meiner Lösung Zeichenfolgenbegrenzer und Qualifizierer anstelle von Zeichen verwendet. Ich fand es schwieriger als ich erwartet hatte, einen guten, generischen CSV-Parser zu finden, daher hoffe ich, dass dieser Algorithmus jemandem helfen kann. 

    public static string[] SplitRow(string record, string delimiter, string qualifier, bool trimData)
    {
        // In-Line for example, but I implemented as string extender in production code
        Func <string, int, int> IndexOfNextNonWhiteSpaceChar = delegate (string source, int startIndex)
        {
            if (startIndex >= 0)
            {
                if (source != null)
                {
                    for (int i = startIndex; i < source.Length; i++)
                    {
                        if (!char.IsWhiteSpace(source[i]))
                        {
                            return i;
                        }
                    }
                }
            }

            return -1;
        };

        var results = new List<string>();
        var result = new StringBuilder();
        var inQualifier = false;
        var inField = false;

        // We add new columns at the delimiter, so append one for the parser.
        var row = $"{record}{delimiter}";

        for (var idx = 0; idx < row.Length; idx++)
        {
            // A delimiter character...
            if (row[idx]== delimiter[0])
            {
                // Are we inside qualifier? If not, we've hit the end of a column value.
                if (!inQualifier)
                {
                    results.Add(trimData ? result.ToString().Trim() : result.ToString());
                    result.Clear();
                    inField = false;
                }
                else
                {
                    result.Append(row[idx]);
                }
            }

            // NOT a delimiter character...
            else
            {
                // ...Not a space character
                if (row[idx] != ' ')
                {
                    // A qualifier character...
                    if (row[idx] == qualifier[0])
                    {
                        // Qualifier is closing qualifier...
                        if (inQualifier && row[IndexOfNextNonWhiteSpaceChar(row, idx + 1)] == delimiter[0])
                        {
                            inQualifier = false;
                            continue;
                        }

                        else
                        {
                            // ...Qualifier is opening qualifier
                            if (!inQualifier)
                            {
                                inQualifier = true;
                            }

                            // ...It's a qualifier inside a qualifier.
                            else
                            {
                                inField = true;
                                result.Append(row[idx]);
                            }
                        }
                    }

                    // Not a qualifier character...
                    else
                    {
                        result.Append(row[idx]);
                        inField = true;
                    }
                }

                // ...A space character
                else
                {
                    if (inQualifier || inField)
                    {
                        result.Append(row[idx]);
                    }
                }
            }
        }

        return results.ToArray<string>();
    }

Einige Testcodes:

        //var input = "111,222,\"33,44,55\",666,\"77,88\",\"99\"";

        var input =
            "111, 222, \"99\",\"33,44,55\" ,      \"666 \"mark of a man\"\", \" spaces \"77,88\"   \"";

        Console.WriteLine("Split with trim");
        Console.WriteLine("---------------");
        var result = SplitRow(input, ",", "\"", true);
        foreach (var r in result)
        {
            Console.WriteLine(r);
        }
        Console.WriteLine("");

        // Split 2
        Console.WriteLine("Split with no trim");
        Console.WriteLine("------------------");
        var result2 = SplitRow(input, ",", "\"", false);
        foreach (var r in result2)
        {
            Console.WriteLine(r);
        }
        Console.WriteLine("");

        // Time Trial 1
        Console.WriteLine("Experimental Process (1,000,000) iterations");
        Console.WriteLine("-------------------------------------------");
        watch = Stopwatch.StartNew();
        for (var i = 0; i < 1000000; i++)
        {
            var x1 = SplitRow(input, ",", "\"", false);
        }
        watch.Stop();
        elapsedMs = watch.ElapsedMilliseconds;
        Console.WriteLine($"Total Process Time: {string.Format("{0:0.###}", elapsedMs / 1000.0)} Seconds");
        Console.WriteLine("");

Ergebnisse

Split with trim
---------------
111
222
99
33,44,55
666 "mark of a man"
spaces "77,88"

Split with no trim
------------------
111
222
99
33,44,55
666 "mark of a man"
 spaces "77,88"

Original Process (1,000,000) iterations
-------------------------------
Total Process Time: 7.538 Seconds

Experimental Process (1,000,000) iterations
--------------------------------------------
Total Process Time: 3.363 Seconds
1
Sam Jazz

Zur Zeit verwende ich folgende Regex:

    public static Regex regexCSVSplit = new Regex(@"(?x:(
        (?<FULL>
        (^|[,;\t\r\n])\s*
        ( (?<CODAT> (?<CO>[""'])(?<DAT>([^,;\t\r\n]|(?<!\k<CO>\s*)[,;\t\r\n])*)\k<CO>) |
          (?<CODAT> (?<DAT> [^""',;\s\r\n]* )) )
        (?=\s*([,;\t\r\n]|$))
        ) |
        (?<FULL>
        (^|[\s\t\r\n])
        ( (?<CODAT> (?<CO>[""'])(?<DAT> [^""',;\s\t\r\n]* )\k<CO>) |
        (?<CODAT> (?<DAT> [^""',;\s\t\r\n]* )) )
        (?=[,;\s\t\r\n]|$))
        ))", RegexOptions.Compiled);

Diese Lösung kann mit ziemlich chaotischen Fällen auch wie folgt umgehen:  enter image description here

So geben Sie das Ergebnis in ein Array ein:

    var data = regexCSVSplit.Matches(line_to_process).Cast<Match>().Select(x => x.Groups["DAT"].Value).ToArray();

Sehen Sie dieses Beispiel in Aktion HIER

1
SchLx

Ich weiß, dass ich etwas spät dran bin, aber für Suchanfragen habe ich in Cisis genau das getan, worauf Sie sich gerade einlassen

private string[] splitString(string stringToSplit)
    {
        char[] characters = stringToSplit.ToCharArray();
        List<string> returnValueList = new List<string>();
        string tempString = "";
        bool blockUntilEndQuote = false;
        int characterCount = 0;
        foreach (char character in characters)
        {
            characterCount = characterCount + 1;

            if (character == '"')
            {
                if (blockUntilEndQuote == false)
                {
                    blockUntilEndQuote = true;
                }
                else if (blockUntilEndQuote == true)
                {
                    blockUntilEndQuote = false;
                }
            }

            if (character != ',')
            {
                tempString = tempString + character;
            }
            else if (character == ',' && blockUntilEndQuote == true)
            {
                tempString = tempString + character;
            }
            else
            {
                returnValueList.Add(tempString);
                tempString = "";
            }

            if (characterCount == characters.Length)
            {
                returnValueList.Add(tempString);
                tempString = "";
            }
        }

        string[] returnValue = returnValueList.ToArray();
        return returnValue;
    }
1
Bbb

Hier ist meine schnellste Implementierung basierend auf der String-Zeiger-Manipulation:

string[] FastSplit(string sText, char? cSeparator = null, char? cQuotes = null)
    {            
        string[] oTokens;

        if (null == cSeparator)
        {
            cSeparator = DEFAULT_PARSEFIELDS_SEPARATOR;
        }

        if (null == cQuotes)
        {
            cQuotes = DEFAULT_PARSEFIELDS_QUOTE;
        }

        unsafe
        {
            fixed (char* lpText = sText)
            {
                #region Fast array estimatation

                char* lpCurrent      = lpText;                    
                int   nEstimatedSize = 0;

                while (0 != *lpCurrent)
                {
                    if (cSeparator == *lpCurrent)
                    {
                        nEstimatedSize++;
                    }

                    lpCurrent++;
                }

                nEstimatedSize++; // Add EOL char(s)
                string[] oEstimatedTokens = new string[nEstimatedSize];

                #endregion

                #region Parsing

                char[] oBuffer = new char[sText.Length];
                int    nIndex  = 0;
                int    nTokens = 0;

                lpCurrent      = lpText;

                while (0 != *lpCurrent)
                {
                    if (cQuotes == *lpCurrent)
                    {
                        // Quotes parsing

                        lpCurrent++; // Skip quote
                        nIndex = 0;  // Reset buffer

                        while (
                               (0       != *lpCurrent)
                            && (cQuotes != *lpCurrent)
                        )
                        {
                            oBuffer[nIndex] = *lpCurrent; // Store char

                            lpCurrent++; // Move source cursor
                            nIndex++;    // Move target cursor
                        }

                    } 
                    else if (cSeparator == *lpCurrent)
                    {
                        // Separator char parsing

                        oEstimatedTokens[nTokens++] = new string(oBuffer, 0, nIndex); // Store token
                        nIndex                      = 0;                              // Skip separator and Reset buffer
                    }
                    else
                    {
                        // Content parsing

                        oBuffer[nIndex] = *lpCurrent; // Store char
                        nIndex++;                     // Move target cursor
                    }

                    lpCurrent++; // Move source cursor
                }

                // Recover pending buffer

                if (nIndex > 0)
                {
                    // Store token

                    oEstimatedTokens[nTokens++] = new string(oBuffer, 0, nIndex);
                }

                // Build final tokens list

                if (nTokens == nEstimatedSize)
                {
                    oTokens = oEstimatedTokens;
                }
                else
                {
                    oTokens = new string[nTokens];
                    Array.Copy(oEstimatedTokens, 0, oTokens, 0, nTokens);
                }

                #endregion
            }
        }

        // Epilogue            

        return oTokens;
    }
0

Versuche dies

private string[] GetCommaSeperatedWords(string sep, string line)
    {
        List<string> list = new List<string>();
        StringBuilder Word = new StringBuilder();
        int doubleQuoteCount = 0;
        for (int i = 0; i < line.Length; i++)
        {
            string chr = line[i].ToString();
            if (chr == "\"")
            {
                if (doubleQuoteCount == 0)
                    doubleQuoteCount++;
                else
                    doubleQuoteCount--;

                continue;
            }
            if (chr == sep && doubleQuoteCount == 0)
            {
                list.Add(Word.ToString());
                Word = new StringBuilder();
                continue;
            }
            Word.Append(chr);
        }

        list.Add(Word.ToString());

        return list.ToArray();
    }
0
Krishna

Dies ist die Antwort von Chad, die mit staatlicher Logik neu geschrieben wurde. Seine Antwort scheiterte für mich, als es """BRAD""" als Feld erschien. Das sollte "BRAD" zurückgeben, aber es fraß nur die restlichen Felder auf. Als ich versuchte, es zu debuggen, schrieb ich es schließlich als zustandsbasierte Logik um:

enum SplitState { s_begin, s_infield, s_inquotefield, s_foundquoteinfield };
public static IEnumerable<string> SplitRow(string row, char delimiter = ',')
{
    var currentString = new StringBuilder();
    SplitState state = SplitState.s_begin;
    row = string.Format("{0}{1}", row, delimiter); //We add new cells at the delimiter, so append one for the parser.
    foreach (var character in row.Select((val, index) => new { val, index }))
    {
        //Console.WriteLine("character = " + character.val + " state = " + state);
        switch (state)
        {
            case SplitState.s_begin:
                if (character.val == delimiter)
                {
                    /* empty field */
                    yield return currentString.ToString();
                    currentString.Clear();
                } else if (character.val == '"')
                {
                    state = SplitState.s_inquotefield;
                } else
                {
                    currentString.Append(character.val);
                    state = SplitState.s_infield;
                }
                break;
            case SplitState.s_infield:
                if (character.val == delimiter)
                {
                    /* field with data */
                    yield return currentString.ToString();
                    state = SplitState.s_begin;
                    currentString.Clear();
                } else
                {
                    currentString.Append(character.val);
                }
                break;
            case SplitState.s_inquotefield:
                if (character.val == '"')
                {
                    // could be end of field, or escaped quote.
                    state = SplitState.s_foundquoteinfield;
                } else
                {
                    currentString.Append(character.val);
                }
                break;
            case SplitState.s_foundquoteinfield:
                if (character.val == '"')
                {
                    // found escaped quote.
                    currentString.Append(character.val);
                    state = SplitState.s_inquotefield;
                }
                else if (character.val == delimiter)
                {
                    // must have been last quote so we must find delimiter
                    yield return currentString.ToString();
                    state = SplitState.s_begin;
                    currentString.Clear();
                }
                else
                {
                    throw new Exception("Quoted field not terminated.");
                }
                break;
            default:
                throw new Exception("unknown state:" + state);
        }
    }
    //Console.WriteLine("currentstring = " + currentString.ToString());
}

Dies sind wesentlich mehr Codezeilen als bei den anderen Lösungen, es ist jedoch leicht zu ändern, um Edge-Fälle hinzuzufügen.

0
Michael Potter

Ich musste einmal etwas Ähnliches machen und am Ende blieb ich bei Regular Expressions hängen. Die Unfähigkeit von Regex, den Status zu haben, macht es ziemlich schwierig - ich habe am Ende einen einfachen kleinen Parser geschrieben.

Wenn Sie CSV-Analyse durchführen, sollten Sie einfach verwenden, indem Sie einen CSV-Parser verwenden - und das Rad nicht neu erfinden.

0
Jaco Pretorius