以前に C# でライブラリを使って CSV を読み込む方法を試しました。
rksoftware.hatenablog.com
しかし少々コードが長くなってしまったので、手軽に使えるスニペットを書いてみました。CSV の読み書き、何度かいても忘れてしまうのでもう書き残しておくことにします。
こんな感じのコードをプロジェクト内においておけば、しゅっと CSV が扱えるかもしれません。品質は保証できませんけれど。
■ 使い方
var csvString = "a,b,c\n1,2,3\n4,5,6\n"; var data = CsvParser.CsvReader.Read(csvString);
var csvString = "a,b,c\n1,2,3\n4,5,6\n"; var (header, data) = CsvParser.CsvReader.ReadHeaderAndData(csvString);
■ CSV 読み込みコード
public static class CsvReader { public static string[][] Read(string csvString) => _Read(csvString); public static (string[] header, string[][] data) ReadHeaderAndData(string csvString) { var values = Read(csvString); return (values.FirstOrDefault() ?? Array.Empty<string>(), values.Skip(1).ToArray()); } private static string[][] _Read(string csvString) { List<List<List<char>>> data = new(); (bool isLineHead, bool isQuoted, char quote, bool isEscaped) = (true, false, '"', false); foreach (var c in csvString) { if (isLineHead) { data.Add(new List<List<char>>()); data.LastOrDefault()?.Add(new List<char>()); isLineHead = false; } if (data.LastOrDefault()?.LastOrDefault()?.Count == 0 && !isQuoted && (c == '"' || c == '\'')) { (isQuoted, quote, isEscaped) = (true, c, false); continue; } if (!isEscaped && isQuoted && c == quote) { isEscaped = true; continue; } if (c == ',' && (!isQuoted || isEscaped)) { data.LastOrDefault()?.Add(new List<char>()); (isQuoted, isEscaped) = (false, false); continue; } if (c == '\n' && (!isQuoted || isEscaped)) { isLineHead = true; (isQuoted, isEscaped) = (false, false); continue; } isEscaped = false; data.LastOrDefault()?.LastOrDefault()?.Add(c); } return data.Select(line => line.Select(cell => new string(cell.ToArray())).ToArray()).ToArray(); } }
■ CSV 文字列化コード
public static class CsvWriter { public static string Write(string[][] data) => _Write(data); public static string Write(string[] header, string[][] data) => Write(new string[][] { header }.Concat(data).ToArray()); private static string _Write(string[][] data) { var sb = new System.Text.StringBuilder(); foreach (var line in data ?? Array.Empty<string[]>()) sb.Append(string.Join(',', line.Select(Escape)) + '\n'); return sb.ToString(); static string Escape(string cell) => (cell.Contains('"') || cell.Contains('\'') || cell.Contains(',') || cell.Contains('\n')) ? $"\"{cell.Replace("\"", "\"\"")}\"" : cell; } }
■ GitHub
このコードは GitHub においています。