意外と難しかったのでメモ。
CsvHelper というライブラリを使っています。
導入方法
dotnet add package CsvHelper
C# で CSV 文字列を CSV としてパースして指定のセルでソートして出力するコードです。内部的にはデータを配列で扱っています。CSV の中身には決まりがないのでデータオブジェクトにマッピングしない、というスタンスでやってみました。
■ コード
// データの読み込みと加工 var (header, data) = ReadAndOrder(args.FirstOrDefault() ?? string.Empty, args.Skip(1).FirstOrDefault() ?? string.Empty); // 結果の出力 ヘッダー行とデータ行 Console.WriteLine(string.Join(",", header.Select(Escape))); Console.WriteLine(string.Join("\n", data.Select(line => string.Join(",", line.Select(Escape))))); //// // == 以降メソッド == //// // データの読み込みと加工メソッド static (string[], string[][]) ReadAndOrder(string csv, string orderCellName) { // データの読み込みとヘッダー行の抽出 var headerAndData = Read(csv).ToArray(); var header = headerAndData.FirstOrDefault() ?? Array.Empty<string>(); // ソートする列のインデックスを産出 var orderCellIndex = header.Index().Where(x => string.Compare(x.Item, orderCellName) == 0).Select(x => x.Index + 1).FirstOrDefault() - 1; // ソートしつつデータ部の抽出 var data = headerAndData.Skip(1).OrderBy(x => (-1 < orderCellIndex && orderCellIndex < x.Length) ? x[orderCellIndex] : "").ToArray(); return (header, data); } // 読み込みメソッド CsvHelper 使用 static IEnumerable<string[]> Read(string csv) { using var sr = new StringReader(csv); using var helper = new CsvHelper.CsvReader(sr, System.Globalization.CultureInfo.CurrentCulture); while (helper.Read()) yield return Enumerable.Range(0, helper.Parser.Count).Select(i => helper.Parser[i]).ToArray(); } // 結果出力時のエスケープ static string Escape(string cell) => (cell.Contains('"') || cell.Contains('\'') || cell.Contains(',') || cell.Contains('\n')) ? $"\"{cell.Replace("\"", "\"\"")}\"" : cell;
■ 実行例
h1 列でソート
.\kaito.exe h1,h2`n3,6`n5,4`n6,5`n4,3 h1 h1,h2 3,6 4,3 5,4 6,5
h2 列でソート
.\kaito.exe h1,h2`n3,6`n5,4`n6,5`n4,3 h2 h1,h2 4,3 5,4 6,5 3,6
■ C# Tokyo お題
このコードは C# Tokyo のお題のコードを書いてみよう企画で書いたコードです。