CSV分割・変換ツール 設計書
概要
このツールは、コマンドライン引数で指定されたCSVファイルを4つの出力ファイルに分割し、各ファイルごとに異なる変換仕様に従って出力する。変換内容には単純な値変換、固定値出力、条件付きスキップ、2段階抽出などが含まれる。
📁 クラス構成
├── Program.cs // エントリポイント
├── CsvRow.cs // 1行分のCSVデータ表現(ラッパー)
├── CsvLoader.cs // CSV読み込みロジック
├── CsvSplitter.cs // 各ファイル向けの抽出処理
├── Converter.cs // 値の変換処理
├── Extractor.cs // ファイルごとの行抽出処理
└── Writer.cs // 分割後CSVの出力処理
🧩 クラス詳細
CsvRow.cs
public class CsvRow
{
private readonly List<string> _columns;
public CsvRow(List<string> columns)
{
_columns = columns;
}
public string this[int index] => index < _columns.Count ? _columns[index] : "";
public List<string> Columns => _columns;
}
CsvLoader.cs
public static class CsvLoader
{
public static List<CsvRow> Load(string path)
{
var rows = new List<CsvRow>();
foreach (var line in File.ReadLines(path))
{
var columns = line.Split(',').ToList();
rows.Add(new CsvRow(columns));
}
return rows;
}
}
CsvSplitter.cs
public static class CsvSplitter
{
public static Dictionary<string, List<CsvRow>> Split(List<CsvRow> rows, List<Func<CsvRow, CsvRow>> extractors, List<string> fileNames)
{
var result = new Dictionary<string, List<CsvRow>>();
for (int i = 0; i < extractors.Count; i++)
{
result[fileNames[i]] = new List<CsvRow>();
}
foreach (var row in rows)
{
for (int i = 0; i < extractors.Count; i++)
{
var extracted = extractors[i](row);
if (extracted != null)
{
result[fileNames[i]].Add(extracted);
}
}
}
return result;
}
}
Converter.cs(変換ロジック)
public static class Converter
{
private static readonly Dictionary<string, Dictionary<string, string>> _conversionRules = new()
{
{ "code1", new Dictionary<string, string> { { "1", "02" }, { "2", "05" } } },
{ "multi_code", new Dictionary<string, string>
{
{ "3", "103" },
{ "8", "108" },
{ "10", "1055" }
}
},
{ "code101", new Dictionary<string, string> { { "3", "555" }, { "6", "777" } } }
};
public static string? Convert(string ruleKey, string input)
{
if (ruleKey == "code101" && input == "0")
return null;
if (_conversionRules.ContainsKey(ruleKey) && _conversionRules[ruleKey].ContainsKey(input))
{
return _conversionRules[ruleKey][input];
}
return null;
}
public static List<string> ConvertAndExpandMultiple(string ruleKey, string input, string fixedValueAfterEach = "01")
{
var results = new List<string>();
if (string.IsNullOrWhiteSpace(input))
{
return results;
}
string[] values = input.Split(',');
foreach (string raw in values)
{
string val = raw.Trim();
if (val == "0" || val == "")
{
continue;
}
if (_conversionRules.ContainsKey(ruleKey) && _conversionRules[ruleKey].ContainsKey(val))
{
string converted = _conversionRules[ruleKey][val];
results.Add(converted);
results.Add(fixedValueAfterEach);
}
}
return results;
}
}
Extractor.cs(抽出ロジック)
public static class Extractor
{
public static CsvRow File1Extractor(CsvRow row)
{
var newColumns = new List<string>();
newColumns.Add(row[0]); // 識別ID
newColumns.Add("01"); // 固定値
string? converted = Converter.Convert("code101", row[101]);
if (converted != null)
{
newColumns.Add(converted);
}
var expanded = Converter.ConvertAndExpandMultiple("multi_code", row[2]);
foreach (var item in expanded)
{
newColumns.Add(item);
}
return new CsvRow(newColumns);
}
}
Writer.cs
public static class Writer
{
public static void WriteCsv(string path, List<CsvRow> rows)
{
using var writer = new StreamWriter(path);
foreach (var row in rows)
{
writer.WriteLine(string.Join(",", row.Columns));
}
}
}
Program.cs(エントリーポイント)
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: CsvTool <input_file>");
return;
}
string inputPath = args[0];
var rows = CsvLoader.Load(inputPath);
var extractors = new List<Func<CsvRow, CsvRow>>
{
Extractor.File1Extractor,
// Extractor.File2Extractor,
// Extractor.File3Extractor,
// Extractor.File4Extractor
};
var fileNames = new List<string>
{
"file1.csv",
"file2.csv",
"file3.csv",
"file4.csv"
};
var splitted = CsvSplitter.Split(rows, extractors, fileNames);
foreach (var kvp in splitted)
{
Writer.WriteCsv(kvp.Key, kvp.Value);
}
}
}