using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace DwgExtractorManual.Models { /// /// Note 데이터를 CSV 파일로 출력하는 클래스 /// Note Box 안의 일반 텍스트와 테이블 텍스트를 분리하여 CSV로 출력 /// public class CsvDataWriter { /// /// Note 박스 안의 일반 텍스트들을 CSV 파일로 저장 /// public void WriteNoteBoxTextToCsv(List noteEntities, string filePath) { if (noteEntities == null || noteEntities.Count == 0) return; var csvLines = new List(); // CSV 헤더 추가 csvLines.Add("Type,Layer,Text,X,Y,SortOrder,Path,FileName"); // Note와 NoteContent 데이터 추출 (테이블 제외) var noteBoxTexts = noteEntities .Where(ne => ne.Type == "Note" || ne.Type == "NoteContent") .OrderBy(ne => ne.SortOrder) .ToList(); foreach (var noteEntity in noteBoxTexts) { var csvLine = $"{EscapeCsvField(noteEntity.Type)}," + $"{EscapeCsvField(noteEntity.Layer)}," + $"{EscapeCsvField(noteEntity.Text)}," + $"{noteEntity.X:F3}," + $"{noteEntity.Y:F3}," + $"{noteEntity.SortOrder}," + $"{EscapeCsvField(noteEntity.Path)}," + $"{EscapeCsvField(noteEntity.FileName)}"; csvLines.Add(csvLine); } // UTF-8 BOM 포함하여 파일 저장 (Excel에서 한글 깨짐 방지) var utf8WithBom = new UTF8Encoding(true); File.WriteAllLines(filePath, csvLines, utf8WithBom); } /// /// Note 박스 안의 테이블 데이터들을 별도 CSV 파일로 저장 /// public void WriteNoteTablesToCsv(List noteEntities, string filePath) { if (noteEntities == null || noteEntities.Count == 0) return; var allCsvLines = new List(); // 테이블 데이터가 있는 Note들 추출 var notesWithTables = noteEntities .Where(ne => ne.Type == "Note" && !string.IsNullOrEmpty(ne.TableCsv)) .OrderByDescending(ne => ne.Y) // Y 좌표로 정렬 (위에서 아래로) .ToList(); foreach (var noteWithTable in notesWithTables) { // Note 정보 헤더 추가 allCsvLines.Add($"=== NOTE: {noteWithTable.Text} (at {noteWithTable.X:F1}, {noteWithTable.Y:F1}) ==="); allCsvLines.Add(""); // 빈 줄 // 테이블 CSV 데이터 추가 var tableLines = noteWithTable.TableCsv.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); allCsvLines.AddRange(tableLines); // Note 간 구분을 위한 빈 줄들 allCsvLines.Add(""); allCsvLines.Add(""); } // UTF-8 BOM 포함하여 파일 저장 var utf8WithBom = new UTF8Encoding(true); File.WriteAllLines(filePath, allCsvLines, utf8WithBom); } /// /// Note 박스와 테이블 데이터를 통합하여 하나의 CSV 파일로 저장 /// public void WriteNoteDataToCombinedCsv(List noteEntities, string filePath) { if (noteEntities == null || noteEntities.Count == 0) return; var csvLines = new List(); // CSV 헤더 추가 csvLines.Add("Type,Layer,Text,X,Y,SortOrder,TableData,Path,FileName"); // 모든 Note 관련 데이터를 SortOrder로 정렬 var sortedNoteEntities = noteEntities .OrderBy(ne => ne.SortOrder) .ToList(); foreach (var noteEntity in sortedNoteEntities) { // 테이블 데이터가 있는 경우 이를 별도 필드로 처리 var tableData = ""; if (noteEntity.Type == "Note" && !string.IsNullOrEmpty(noteEntity.TableCsv)) { // 테이블 CSV 데이터를 하나의 필드로 압축 (줄바꿈을 |로 대체) tableData = noteEntity.TableCsv.Replace("\n", "|").Replace("\r", ""); } var csvLine = $"{EscapeCsvField(noteEntity.Type)}," + $"{EscapeCsvField(noteEntity.Layer)}," + $"{EscapeCsvField(noteEntity.Text)}," + $"{noteEntity.X:F3}," + $"{noteEntity.Y:F3}," + $"{noteEntity.SortOrder}," + $"{EscapeCsvField(tableData)}," + $"{EscapeCsvField(noteEntity.Path)}," + $"{EscapeCsvField(noteEntity.FileName)}"; csvLines.Add(csvLine); } // UTF-8 BOM 포함하여 파일 저장 var utf8WithBom = new UTF8Encoding(true); File.WriteAllLines(filePath, csvLines, utf8WithBom); } /// /// 각 Note별로 개별 CSV 파일 생성 (테이블이 있는 경우) /// public void WriteIndividualNoteTablesCsv(List noteEntities, string baseDirectory) { if (noteEntities == null || noteEntities.Count == 0) return; // 디렉토리가 없으면 생성 if (!Directory.Exists(baseDirectory)) { Directory.CreateDirectory(baseDirectory); } var notesWithTables = noteEntities .Where(ne => ne.Type == "Note" && !string.IsNullOrEmpty(ne.TableCsv)) .OrderByDescending(ne => ne.Y) .ToList(); int noteIndex = 1; foreach (var noteWithTable in notesWithTables) { // 파일명 생성 (특수문자 제거) var safeNoteText = MakeSafeFileName(noteWithTable.Text); var fileName = $"Note_{noteIndex:D2}_{safeNoteText}.csv"; var fullPath = Path.Combine(baseDirectory, fileName); // 테이블 CSV 데이터를 파일로 저장 var tableLines = noteWithTable.TableCsv.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var utf8WithBom = new UTF8Encoding(true); File.WriteAllLines(fullPath, tableLines, utf8WithBom); noteIndex++; } } /// /// CSV 필드에서 특수문자를 이스케이프 처리 /// private string EscapeCsvField(string field) { if (string.IsNullOrEmpty(field)) return ""; // 쉼표, 따옴표, 줄바꿈이 있으면 따옴표로 감싸기 if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r")) { return "\"" + field.Replace("\"", "\"\"") + "\""; } return field; } /// /// 파일명에 사용할 수 없는 문자들을 제거하여 안전한 파일명 생성 /// private string MakeSafeFileName(string fileName) { if (string.IsNullOrEmpty(fileName)) return "Unknown"; var invalidChars = Path.GetInvalidFileNameChars(); var safeFileName = fileName; foreach (var invalidChar in invalidChars) { safeFileName = safeFileName.Replace(invalidChar, '_'); } // 길이 제한 (Windows 파일명 제한 고려) if (safeFileName.Length > 50) { safeFileName = safeFileName.Substring(0, 50); } return safeFileName.Trim(); } /// /// Note 데이터 통계 정보를 CSV로 저장 /// public void WriteNoteStatisticsToCsv(List noteEntities, string filePath) { if (noteEntities == null || noteEntities.Count == 0) return; var csvLines = new List(); // 통계 헤더 csvLines.Add("Statistic,Count,Details"); // 전체 Note 개수 var totalNotes = noteEntities.Count(ne => ne.Type == "Note"); csvLines.Add($"Total Notes,{totalNotes},"); // 테이블이 있는 Note 개수 var notesWithTables = noteEntities.Count(ne => ne.Type == "Note" && !string.IsNullOrEmpty(ne.TableCsv)); csvLines.Add($"Notes with Tables,{notesWithTables},"); // 일반 텍스트만 있는 Note 개수 var notesWithTextOnly = totalNotes - notesWithTables; csvLines.Add($"Notes with Text Only,{notesWithTextOnly},"); // 전체 Note 콘텐츠 개수 var totalNoteContents = noteEntities.Count(ne => ne.Type == "NoteContent"); csvLines.Add($"Total Note Contents,{totalNoteContents},"); // 레이어별 분포 csvLines.Add(",,"); csvLines.Add("Layer Distribution,,"); var layerGroups = noteEntities .GroupBy(ne => ne.Layer) .OrderByDescending(g => g.Count()) .ToList(); foreach (var layerGroup in layerGroups) { csvLines.Add($"Layer: {layerGroup.Key},{layerGroup.Count()},"); } var utf8WithBom = new UTF8Encoding(true); File.WriteAllLines(filePath, csvLines, utf8WithBom); } } }