Files
manual_wpf/Models/CsvDataWriter.cs
2025-08-12 14:33:18 +09:00

261 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace DwgExtractorManual.Models
{
/// <summary>
/// Note 데이터를 CSV 파일로 출력하는 클래스
/// Note Box 안의 일반 텍스트와 테이블 텍스트를 분리하여 CSV로 출력
/// </summary>
public class CsvDataWriter
{
/// <summary>
/// Note 박스 안의 일반 텍스트들을 CSV 파일로 저장
/// </summary>
public void WriteNoteBoxTextToCsv(List<NoteEntityInfo> noteEntities, string filePath)
{
if (noteEntities == null || noteEntities.Count == 0)
return;
var csvLines = new List<string>();
// 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);
}
/// <summary>
/// Note 박스 안의 테이블 데이터들을 별도 CSV 파일로 저장
/// </summary>
public void WriteNoteTablesToCsv(List<NoteEntityInfo> noteEntities, string filePath)
{
if (noteEntities == null || noteEntities.Count == 0)
return;
var allCsvLines = new List<string>();
// 테이블 데이터가 있는 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);
}
/// <summary>
/// Note 박스와 테이블 데이터를 통합하여 하나의 CSV 파일로 저장
/// </summary>
public void WriteNoteDataToCombinedCsv(List<NoteEntityInfo> noteEntities, string filePath)
{
if (noteEntities == null || noteEntities.Count == 0)
return;
var csvLines = new List<string>();
// 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);
}
/// <summary>
/// 각 Note별로 개별 CSV 파일 생성 (테이블이 있는 경우)
/// </summary>
public void WriteIndividualNoteTablesCsv(List<NoteEntityInfo> 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++;
}
}
/// <summary>
/// CSV 필드에서 특수문자를 이스케이프 처리
/// </summary>
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;
}
/// <summary>
/// 파일명에 사용할 수 없는 문자들을 제거하여 안전한 파일명 생성
/// </summary>
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();
}
/// <summary>
/// Note 데이터 통계 정보를 CSV로 저장
/// </summary>
public void WriteNoteStatisticsToCsv(List<NoteEntityInfo> noteEntities, string filePath)
{
if (noteEntities == null || noteEntities.Count == 0)
return;
var csvLines = new List<string>();
// 통계 헤더
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);
}
}
}