| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using LocalizationTool.Models;
- namespace LocalizationTool.Services
- {
- /// <summary>
- /// CSV 导入导出(逗号分隔,Excel 可直接打开编辑)。
- /// 列结构与主界面表格一致:第一列"中文原文",其后为各语言代码列(en-US、ja-JP…)。
- /// 导出 UTF-8 带 BOM(Excel 中文不乱码);导入兼容 UTF-8 与 ANSI(GB18030)。
- /// </summary>
- public static class CsvExchange
- {
- /// <summary>导出表格行到 CSV 文件。langs 决定语言列(与表格当前勾选列一致)。</summary>
- public static void Export(string path, IEnumerable<RowVm> rows, List<PackFile> langs)
- {
- var sb = new StringBuilder();
- sb.AppendLine(JoinCsv(new[] { "中文原文" }.Concat(langs.Select(l => l.LanguageCode))));
- foreach (var r in rows)
- {
- var fields = new List<string> { r.Key };
- foreach (var l in langs)
- fields.Add(r.Cells.TryGetValue(l.LanguageCode, out var c) ? c.Value : "");
- sb.AppendLine(JoinCsv(fields));
- }
- File.WriteAllText(path, sb.ToString(), new UTF8Encoding(true)); // BOM:Excel 识别 UTF-8
- }
- /// <summary>解析 CSV 文件:返回 (表头, 数据行)。空行跳过;引号/逗号/换行转义按 RFC4180 处理。</summary>
- public static Tuple<List<string>, List<string[]>> Parse(string path)
- {
- var bytes = File.ReadAllBytes(path);
- if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
- bytes = bytes.Skip(3).ToArray();
- string text;
- try { text = new UTF8Encoding(false, true).GetString(bytes); }
- catch { text = Encoding.GetEncoding("gb18030").GetString(bytes); } // Excel 另存的 ANSI CSV
- var header = new List<string>();
- var records = new List<string[]>();
- using (var reader = new StringReader(text))
- using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader))
- {
- parser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited;
- parser.SetDelimiters(",");
- parser.HasFieldsEnclosedInQuotes = true;
- while (!parser.EndOfData)
- {
- string[] fields;
- try { fields = parser.ReadFields(); }
- catch (Microsoft.VisualBasic.FileIO.MalformedLineException)
- {
- throw new Exception($"第 {parser.ErrorLineNumber} 行格式错误(常见原因:引号未闭合)");
- }
- if (fields == null) continue;
- if (fields.All(string.IsNullOrWhiteSpace)) continue;
- if (header.Count == 0) { header.AddRange(fields); continue; }
- records.Add(fields);
- }
- }
- return Tuple.Create(header, records);
- }
- private static string JoinCsv(IEnumerable<string> fields) =>
- string.Join(",", fields.Select(Escape));
- private static string Escape(string field)
- {
- field = field ?? "";
- if (field.IndexOfAny(new[] { ',', '"', '\r', '\n' }) >= 0)
- return "\"" + field.Replace("\"", "\"\"") + "\"";
- return field;
- }
- }
- }
|