2

C# コードで解析する必要がある大きな文字列があります (実際には CSV ファイルではありませんが、CSV ファイルと呼びましょう)。解析プロセスの最初のステップでは、オブジェクトを使用してファイルを処理するまで呼び出す
だけで、ファイルを個々の行に分割します。ただし、特定の行には、改行が埋め込まれた引用符で囲まれた (一重引用符で囲まれた) リテラルが含まれている場合があります。これらの改行を見つけて、ファイルを行の配列に分割するまで、それらを一時的に他の種類のトークンまたはエスケープ シーケンスに変換する必要があります。その後、それらを元に戻すことができます。StreamReaderReadLine

入力データの例:

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

これを行うために必要なすべての C# コードをstring.IndexOf、引用されたセクションを見つけて改行を探すために書くことができましたが、正規表現の方が良い選択かもしれないと考えています (つまり、2 つの問題があります) 。

4

4 に答える 4

3

これは真の CSV ファイルではないため、何らかのスキーマはありますか?

あなたの例から、あなたが持っているように見えます: int, int, int, int, string , bool, bool, int

それがあなたのレコード/オブジェクトを構成しています。

データが適切に形成されていると仮定します(この仮定がどれほど有効かを知るには、ソースについて十分に知りません); あなたは出来る:

  1. あなたの行を読んでください。
  2. ステート マシンを使用してデータを解析します。
  3. 行が終了し、文字列を解析している場合は、次の行を読んで解析を続けます。

可能であれば、正規表現の使用は避けたいと思います。

于 2008-08-28T19:00:02.280 に答える
3

このようなジョブを実行するためのステート マシンは、C# 2.0 イテレータを使用して簡単に作成できます。これが、私が書く最後の CSV パーサーになることを願っています。ファイル全体は、列挙可能な文字列、つまり行/列の列挙可能な束として扱われます。IEnumerable は、LINQ 演算子によって処理できるため、優れています。

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();
    }

}

ファイルは、改行を行区切り記号または引用符で囲まれた文字列の一部としていつ処理するかを決定するコードを使用して、1 文字ずつ読み取られることに注意してください。

于 2008-08-28T19:20:07.630 に答える
1

ファイル全体を変数に入れ、それを引用符で囲まれていない改行に基づいて分割するとどうなりますか?

于 2008-08-28T18:51:03.113 に答える
0

編集:申し訳ありませんが、私はあなたの投稿を誤解しました. 正規表現を探している場合は、次のとおりです。

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

特殊なケースとその 2 つの問題があるかもしれませんが、ほとんどの場合は問題ないと思います。Regex が行うことは、最初に \n を含む一重引用符のペアを見つけ、その \n を TOKEN に置き換えてその間のテキストを保持することです。

それでも、@bryanshが以下で説明したように、ステートマシンに行きます。

于 2008-08-28T18:50:32.833 に答える