Suche nach Regex zu finden, zitiert Zeilenumbrüche in eine große Zeichenfolge (für C#)

StackOverflow https://stackoverflow.com/questions/33063

  •  09-06-2019
  •  | 
  •  

Frage

Ich habe eine große Zeichenfolge (nennen wir es eine CSV-Datei, obwohl es nicht wirklich ein, wird es nur einfacher für jetzt), dass ich zu analysieren, die in C# code.
Der erste Schritt der parsing-Prozess teilt die Datei in einzelne Linien, die nur mit einem StreamReader Objekt und ruft ReadLine bis es durch die Datei.Jedoch, jede gegebene Zeile könnte enthalten zitiert (in Anführungszeichen) literal mit eingebetteten Zeilenumbrüchen.Ich brauche zu finden, die Zeilenumbrüche und konvertieren Sie Sie vorübergehend in eine andere Art von token oder einer escape-Sequenz, bis ich habe, teilen Sie die Datei in ein array von Zeilen..dann kann ich ändern Sie Sie zurück.

Beispiel input-Daten:

1,2,10,99,'Some text without a newline', true, false, 90
2,1,11,98,'This text has an embedded newline 
                and continues here', true, true, 90

Ich könnte schreiben von C# - code, der benötigt wird, um dies zu tun, indem Sie mit string.IndexOf zu finden, die zitierten Abschnitte und sehen in Ihnen für Zeilenumbrüche, aber ich denke, ein Regex könnte die bessere Wahl sein (d.h. jetzt habe ich zwei Probleme)

War es hilfreich?

Lösung

Da dieses ist nicht eine echte CSV Datei, gibt es irgendeine Art von schema?

Von Ihrem Beispiel, sieht es aus wie Sie:int, int, int, int, string , bool, bool, int

Mit diesem making up your Datensatz / Objekt.

Unter der Annahme, dass Ihre Daten gut gebildet (ich weiß nicht genug über Ihre Quelle zu wissen, wie gültig diese Annahme ist);Sie könnten:

  1. Lesen Sie Ihre Linie.
  2. Verwenden Sie eine state-Maschine zu analysieren Ihrer Daten.
  3. Wenn Sie Ihre Linie endet, und du bist analysieren einer Zeichenfolge, Lesen Sie die nächste Zeile..und halten analysieren.

Ich möchte vermeiden, eine regex, wenn möglich.

Andere Tipps

Zustand Maschinen, die für die Durchführung einer solchen Arbeit leicht gemacht mit C# 2.0-Iteratoren.Hier ist hoffentlich der Letzte CSV-parser, die ich jemals zu schreiben.Die gesamte Datei wird behandelt wie ein zählbare Reihe von enumerable Saiten, D. H.Zeilen/Spalten.IEnumerable ist großartig, denn es kann dann bearbeitet werden, indem Sie LINQ-Operatoren.

public class CsvParser
{
    public char FieldDelimiter { get; set; }

    public CsvParser()
        : this(',')
    {
    }

    public CsvParser(char fieldDelimiter)
    {
        FieldDelimiter = fieldDelimiter;
    }

    public IEnumerable<IEnumerable<string>> Parse(string text)
    {
        return Parse(new StringReader(text));
    }
    public IEnumerable<IEnumerable<string>> Parse(TextReader reader)
    {
        while (reader.Peek() != -1)
            yield return parseLine(reader);
    }

    IEnumerable<string> parseLine(TextReader reader)
    {
        bool insideQuotes = false;
        StringBuilder item = new StringBuilder();

        while (reader.Peek() != -1)
        {
            char ch = (char)reader.Read();
            char? nextCh = reader.Peek() > -1 ? (char)reader.Peek() : (char?)null;

            if (!insideQuotes && ch == FieldDelimiter)
            {
                yield return item.ToString();
                item.Length = 0;
            }
            else if (!insideQuotes && ch == '\r' && nextCh == '\n') //CRLF
            {
                reader.Read(); // skip LF
                break;
            }
            else if (!insideQuotes && ch == '\n') //LF for *nix-style line endings
                break;
            else if (ch == '"' && nextCh == '"') // escaped quotes ""
            {
                item.Append('"');
                reader.Read(); // skip next "
            }
            else if (ch == '"')
                insideQuotes = !insideQuotes;
            else
                item.Append(ch);
        }
        // last one
        yield return item.ToString();
    }

}

Beachten Sie, dass die Datei gelesen wird Zeichen für Zeichen mit dem code für die Entscheidung, Wann Zeilenumbrüche behandelt werden als Zeilen-Trennzeichen oder Teil einer Zeichenfolge in Anführungszeichen.

Was, wenn du die ganze Datei in eine variable teilen Sie Sie dann, dass der nicht-zitierten newlines?

EDIT: Sorry, hab ich falsch interpretiert Ihre post.Wenn Sie auf der Suche nach einer regex, dann ist hier ein:

content = Regex.Replace(content, "'([^']*)\n([^']*)'", "'\1TOKEN\2'");

Es könnte sein, edge-Fällen, und das sind zwei Probleme, aber ich denke, es sollte in Ordnung sein, die meisten der Zeit.Was die Regex tut, ist, dass es zuerst findet jedes paar von einfachen Anführungszeichen, das hat zwischen es und ersetzen Sie mit TOKEN Erhaltung beliebigen text in-zwischen.

Aber dennoch, ich würde gehen, state-Maschine wie das, was @bryansh unten erklärt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top