読者です 読者をやめる 読者になる 読者になる

C#でstringに格納されているCSVを処理する

C# .NET
  • ファイルからCSVを読み込む例は多かったけどstringに格納されたCSVの処理があんまりなかったのでメモ。

対象文字列の処理

  • _msgというstringに入ってきた複数行のCSVデータを1行づつバラす。
    • Split()は文字列指定ができる。
string[] lines = _msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
  • CSVを処理するのにstreamが都合がいいのでstringを変換する
string[] lines = _msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines.Select((v, i) => new { v, i }))
{
    using (Stream stream = new MemoryStream(Encoding.Default.GetBytes(line.v)))
    {
        // CSV処理
    }
}

CSVの処理

  • stringのSplit(',')だと当然ながらカラムの中にカンマが出てきたらずれてしまうのでMicrosoft.VisualBasic.FileIO.TextFieldParserを使う。
using Microsoft.VisualBasic.FileIO;

TextFieldParser parser = new TextFieldParser(stream, Encoding.GetEncoding("shift_jis"));
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
try
{
    string[] csvData = parser.ReadFields();
    // CSV処理
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

サンプル

  • _msgには1行目にヘッダ、2行目以降にCSVデータが入ってくる想定。
    • コンソールアプリから実行した別のコマンドの結果をパースする想定でEncodingを指定。
using Microsoft.VisualBasic.FileIO;

_msg = FooMethod();
string[] lines = _msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

foreach (var line in lines.Select((v, i) => new { v, i }))
{
    using (Stream stream = new MemoryStream(Encoding.Default.GetBytes(line.v)))
    {
        TextFieldParser parser = new TextFieldParser(stream, Encoding.GetEncoding("shift_jis"));
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");

        try
        {
            if (line.i == 0)
            {
                string[] csvHeader = parser.ReadFields();
            }
            else
            {
                string[] csvData = parser.ReadFields();
                foreach (var item in csvData.Select((v, i) => new { v, i }))
                {
                    Console.WriteLine(string.Format("  {0} : {1}", csvHeader[item.i], item.v));
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

.NETなのに、意外とシャキッと処理できないもんだよなぁ。