以前に 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 においています。
github.com