From 8bc8b4f7b134d07115f43243532c0afbe81e8f6d Mon Sep 17 00:00:00 2001 From: luxuia Date: Sun, 16 Jun 2024 12:26:09 +0800 Subject: [PATCH] add common excel diff --- ExcelMerge/ExcelGridControl.xaml.cs | 4 +- ExcelMerge/MainWindow.xaml.cs | 322 +++++++++++++++--- ExcelMerge/NetDiff/DiffUtil.cs | 74 ++-- ExcelMerge/Util.cs | 15 + "test/\346\265\213\350\257\2251_1.xls" | Bin 17408 -> 0 bytes "test/\346\265\213\350\257\2251_2.xls" | Bin 17920 -> 0 bytes ...350\257\225\345\210\206\351\241\2651.xlsx" | Bin 9386 -> 10736 bytes ...350\257\225\345\210\206\351\241\2652.xlsx" | Bin 8284 -> 9228 bytes 8 files changed, 331 insertions(+), 84 deletions(-) delete mode 100644 "test/\346\265\213\350\257\2251_1.xls" delete mode 100644 "test/\346\265\213\350\257\2251_2.xls" diff --git a/ExcelMerge/ExcelGridControl.xaml.cs b/ExcelMerge/ExcelGridControl.xaml.cs index fbacfc6..ae77f22 100644 --- a/ExcelMerge/ExcelGridControl.xaml.cs +++ b/ExcelMerge/ExcelGridControl.xaml.cs @@ -186,7 +186,7 @@ public void RefreshData() { var headerStr = new string[columnCount]; - var needChangeHead = MainWindow.instance.ProcessHeader.IsChecked == true; + var needChangeHead = status.isConfigDiff; if (needChangeHead) { var headershow = sheet.GetRow(MainWindow.instance.config.ShowLineID-1 + startrow); var headerkey = sheet.GetRow(MainWindow.instance.config.KeyLineID-1 +startrow); @@ -230,7 +230,7 @@ public void RefreshData() { var str = (i + 1).ToString(); var tc = new DataGridTemplateColumn(); - tc.Header = str; + tc.Header = Util.NumberToExcelColumnId(i+1); tc.CellTemplateSelector = new CellTemplateSelector(str, i, tag); tc.CellEditingTemplateSelector = new CellTemplateSelector(str, i, tag); diff --git a/ExcelMerge/MainWindow.xaml.cs b/ExcelMerge/MainWindow.xaml.cs index b701d12..3dcfe44 100644 --- a/ExcelMerge/MainWindow.xaml.cs +++ b/ExcelMerge/MainWindow.xaml.cs @@ -146,7 +146,7 @@ void UpdateSVNRevision(string file, string tag) { } } - + //计算修改的列id 是 对应的第几列 int[] getColumn2Diff(List> diff, bool from) { int idx = 0; var ret = new int[diff.Count]; @@ -165,10 +165,14 @@ int[] getColumn2Diff(List> diff, bool from) { return ret; } - // 对比两个sheet - SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) { - status = status??new SheetDiffStatus() { sortKey = config.DefaultKeyID }; + // 对比两个配置表格式的excel + SheetDiffStatus DiffConfigSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) + { + if (src == null || dst == null) + { + return null; + } bool changed = false; var srcwrap = books["src"]; @@ -176,7 +180,9 @@ SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) var head1 = GetHeaderStrList(srcwrap, src); var head2 = GetHeaderStrList(dstwrap, dst); - if (head1 == null || head2 == null) return null; + if (head1 == null || head2 == null || head1.Count == 0 || head2.Count == 0) return null; + + status = status ?? new SheetDiffStatus() { sortKey = config.DefaultKeyID }; var diff = NetDiff.DiffUtil.Diff(head1, head2); //var optimized = diff.ToList();// NetDiff.DiffUtil.OptimizeCaseDeletedFirst(diff); @@ -192,7 +198,7 @@ SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) srcwrap.SheetValideColumn[src.SheetName] = head1.Count; dstwrap.SheetValideColumn[dst.SheetName] = head2.Count; - + status.diffFistColumn = GetIDDiffList(src, dst, 1, false, status.sortKey); changed = changed || status.diffFistColumn.Any(a => a.Status != DiffStatus.Equal); @@ -212,7 +218,7 @@ SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) if (diffkv.Obj1.Key == null) { // 创建新行,方便比较,放在后面是为了保证diff的时候是new,delete的形式,而不是modify - rowid1 = books["src"].SheetValideRow[src.SheetName]; + rowid1 = books["src"].SheetValideRow[src.SheetName]; //src.CreateRow(rowid1); } if (diffkv.Obj2.Key == null) { @@ -234,6 +240,181 @@ SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) var rowdiff = new SheetRowDiff(); rowdiff.diffcells = diffrow; + rowdiff.changed = diffrow.Any(a => a.Status != DiffStatus.Equal); + if (rowdiff.changed) + { + rowdiff.diffcell_details = new List>>(); + foreach (var cell in diffrow) + { + if (cell.Status == DiffStatus.Modified) + { + var cell_diff = NetDiff.DiffUtil.Diff(cell.Obj1, cell.Obj2); + //var optimized = diff.ToList();// NetDiff.DiffUtil.OptimizeCaseDeletedFirst(diff); + var opt_cell_diff = DiffUtil.OptimizeCaseDeletedFirst(cell_diff); + + rowdiff.diffcell_details.Add(opt_cell_diff.ToList()); + } + else + { + rowdiff.diffcell_details.Add(null); + } + } + } + status.diffSheet.Add(rowdiff); + + changed = changed || rowdiff.changed; + } + + status.changed = changed; + status.isConfigDiff = true; + + return status; + } + + bool isConfigSheet(ISheet src, ISheet dst) + { + return true; + } + + // 对比两个sheet + SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) + { + SheetDiffStatus ret = null; + if (ProcessHeader.IsChecked == true) + { + ret = DiffConfigSheet(src, dst, status); + } + if (ret == null) { + ret = DiffCommonSheet(src, dst, status); + } + return ret; + } + List GetCommonHeaderStrList(WorkBookWrap wrap, ISheet sheet) + { + List header = new List(); + + if (sheet != null) + { + var it = sheet.GetRowEnumerator(); + var min_col = 10000000; + var max_col = -1; + var min_row = 10000000; + var max_row = -1; + while (it.MoveNext()) + { + if (it.Current is IRow row){ + min_col = Math.Min(row.FirstCellNum, min_col); + max_col = Math.Max(row.LastCellNum, max_col); + + min_row = Math.Min(row.RowNum, min_row); + max_row = Math.Max(row.RowNum, max_row); + } + } + + if (max_col > 0 ) + { + wrap.SheetValideRow[sheet.SheetName] = max_row; + wrap.SheetStartPoint[sheet.SheetName] = new Tuple(min_row, 0); + + for (var i = 0; i <= max_col; i++) + { + header.Add((i+1).ToString()); + } + } + } + return header; + } + + List> GetCommonIDDiffList(ISheet sheet1, ISheet sheet2) + { + + Action> search = (WorkBookWrap wrap, ISheet sheet, List list) => { + var nameHash = new HashSet(); + + var max_idx = wrap.SheetValideRow[sheet.SheetName]; + var min_idx = wrap.SheetStartPoint[sheet.SheetName]; + + for (var i = 0; i <= max_idx; ++i) + { + list.Add(new string2int(i.ToString(), i)); + } + }; + var list1 = new List(); + var list2 = new List(); + + search(books["src"], sheet1, list1); + search(books["dst"], sheet2, list2); + + var option = new DiffOption(); + option.EqualityComparer = new SheetIDComparer(); + var result = DiffUtil.Diff(list1, list2, option); + //var optimize = result.ToList();// + // id列不应该把delete/add优化成modify + // var optimize = DiffUtil.OptimizeCaseDeletedFirst(result); + return result.ToList(); + } + private SheetDiffStatus DiffCommonSheet(ISheet src, ISheet dst, SheetDiffStatus status) + { + status = status ?? new SheetDiffStatus() { sortKey = config.DefaultKeyID }; + + bool changed = false; + + var srcwrap = books["src"]; + var dstwrap = books["dst"]; + + var head1 = GetCommonHeaderStrList(srcwrap, src); + var head2 = GetCommonHeaderStrList(dstwrap, dst); + + var diff = NetDiff.DiffUtil.Diff(head1, head2); + //var optimized = diff.ToList();// NetDiff.DiffUtil.OptimizeCaseDeletedFirst(diff); + var optimized = DiffUtil.OptimizeCaseDeletedFirst(diff); + + changed = changed || optimized.Any(a => a.Status != DiffStatus.Equal); + + var diffhead = optimized.ToList(); + status.diffHead = new SheetRowDiff() { diffcells = diffhead }; + + status.column2diff1[0] = getColumn2Diff(diffhead, true); + status.column2diff2[0] = getColumn2Diff(diffhead, false); + + srcwrap.SheetValideColumn[src.SheetName] = head1.Count; + dstwrap.SheetValideColumn[dst.SheetName] = head2.Count; + + status.diffFistColumn = GetCommonIDDiffList(src, dst); + + changed = changed || status.diffFistColumn.Any(a => a.Status != DiffStatus.Equal); + + foreach (var diffkv in status.diffFistColumn) + { + var rowid1 = diffkv.Obj1.Value; + var rowid2 = diffkv.Obj2.Value; + if (diffkv.Obj1.Key == null) + { + // 创建新行,方便比较 + rowid1 = -1; + } + if (diffkv.Obj2.Key == null) + { + rowid2 = -1; + } + int maxLineCount = 0; + var diffrow = DiffCommonSheetRow(src, rowid1, dst, rowid2, status, out maxLineCount); + + status.column2diff1[rowid1] = getColumn2Diff(diffrow, true); + status.column2diff2[rowid2] = getColumn2Diff(diffrow, false); + + int diffIdx = status.diffSheet.Count; + status.DiffMaxLineCount[diffIdx] = maxLineCount; + + status.rowID2DiffMap1[rowid1] = diffIdx; + status.rowID2DiffMap2[rowid2] = diffIdx; + + status.Diff2RowID1[diffIdx] = rowid1; + status.Diff2RowID2[diffIdx] = rowid2; + + var rowdiff = new SheetRowDiff(); + rowdiff.diffcells = diffrow; + rowdiff.changed = diffrow.Any(a => a.Status != DiffStatus.Equal); if (rowdiff.changed) { rowdiff.diffcell_details = new List>>(); @@ -250,15 +431,16 @@ SheetDiffStatus DiffSheet(ISheet src, ISheet dst, SheetDiffStatus status = null) } } status.diffSheet.Add(rowdiff); - + changed = changed || rowdiff.changed; } status.changed = changed; + status.isConfigDiff = false; return status; } - + public void Refresh() { var file1 = Entrance.SrcFile; var file2 = Entrance.DstFile; @@ -296,6 +478,7 @@ public void Refresh() { sheetsDiff[name] = DiffSheet(src.book.GetSheetAt(sheet1), dst.book.GetSheetAt(sheet2)); if (sheetsDiff[name] != null) { + // 找第一个不相同的sheet oldsheetName = sheetname.Obj1.Name; var sheetidx = 0; if (!string.IsNullOrEmpty(oldsheetName)) { @@ -314,9 +497,6 @@ public void Refresh() { dstSheetID = sheetidx; } } - } else - { - // 新增sheet,直接完整显示 } } @@ -492,43 +672,29 @@ List GetHeaderStrList(WorkBookWrap wrap, ISheet sheet) { var startpoint = wrap.SheetStartPoint[sheet.SheetName]; var startrow = startpoint.Item1; var startcol = startpoint.Item2; - if (ProcessHeader.IsChecked == true) { - var list = new List(); - for (int i = startrow; i < DiffStartIdx(startrow); ++i) { - var row = sheet.GetRow(i); - if (row == null) continue; - list.Add(row); + var list = new List(); + for (int i = startrow; i < DiffStartIdx(startrow); ++i) { + var row = sheet.GetRow(i); + if (row == null) continue; + list.Add(row); + } + + if (list.Count == 0) + { + return null; + } + for (int i = startcol; i < list[0].Cells.Count; ++i) { + var str = ""; + for (int j = 0; j < list.Count; ++j) { + var cell_s = Util.GetCellValue(list[j].GetCell(i)); + + str = str + (j > 0 ? ":" + cell_s : cell_s); } - - if (list.Count == 0) + if (string.IsNullOrWhiteSpace(str)) { - return null; - } - for (int i = startcol; i < list[0].Cells.Count; ++i) { - var str = ""; - for (int j = 0; j < list.Count; ++j) { - var cell_s = Util.GetCellValue(list[j].GetCell(i)); - - str = str + (j > 0 ? ":" + cell_s : cell_s); - } - if (string.IsNullOrWhiteSpace(str)) - { - return header; - } - header.Add(str); - } - } else { - var row0 = sheet.GetRow(startrow); - if (row0 == null ) return null; - - for (int i = startcol; i < row0.Cells.Count; ++i) { - var s1 = Util.GetCellValue(row0.GetCell(i)); - // 起码有两列 - if (string.IsNullOrWhiteSpace(s1) && i > 1) { - return header; - } - header.Add((i+1).ToString()); + return header; } + header.Add(str); } return header; } @@ -679,6 +845,70 @@ List> DiffSheetRow(ISheet sheet1, int row1, ISheet sheet2, in return optimized.ToList(); } + List> DiffCommonSheetRow(ISheet sheet1, int row1, ISheet sheet2, int row2, SheetDiffStatus status, out int maxLineCount) + { + var list1 = new List(); + var list2 = new List(); + + int maxlinecount = 0; + var sheetname = sheet1.SheetName; + Action> AddList = (WorkBookWrap book, ISheet sheet, int rowid, List ret) => + { + var row = sheet.GetRow(rowid); + var columnCount = book.SheetValideColumn[sheetname]; + var columnstart = book.SheetStartPoint[sheetname].Item2; + + var rowCount = book.SheetValideRow[sheetname]; + var rowstart = book.SheetStartPoint[sheetname].Item1; + + if (rowid >= rowstart && rowid <= rowCount) + { + for (int i = 0; i < columnCount; ++i) + { + var value = row != null ? Util.GetCellValue(row.GetCell(i + columnstart)) : ""; + maxlinecount = Math.Max(maxlinecount, value.Count((c) => { return c == '\n'; }) + 1); + + ret.Add(value); + } + } + }; + AddList(books["src"], sheet1, row1, list1); + AddList(books["dst"], sheet2, row2, list2); + + maxLineCount = maxlinecount; + + var diff = new List>(); + for (int i = 0; i < Math.Max(list1.Count, list2.Count); ++i) + { + + string v1 = i < list1.Count ? list1[i] : null; + string v2 = i < list2.Count ? list2[i] : null; + var op = DiffStatus.Equal; + + + if (v1 == null) + { + op = DiffStatus.Inserted; + } else if (v2 == null) + { + op = DiffStatus.Deleted; + } else + { + if (v1 == v2) + { + op = DiffStatus.Equal; + } + else + { + op = DiffStatus.Modified; + } + } + diff.Add(new DiffResult(v1, v2, op)); + } + + return diff; + } + void OnSheetChanged() { List keys = new List(); diff --git a/ExcelMerge/NetDiff/DiffUtil.cs b/ExcelMerge/NetDiff/DiffUtil.cs index 1a5070b..32c1272 100644 --- a/ExcelMerge/NetDiff/DiffUtil.cs +++ b/ExcelMerge/NetDiff/DiffUtil.cs @@ -135,51 +135,53 @@ public static IEnumerable> OptimizeShift(IEnumerable>(); - while (i < j + optCount) { - var obj1 = deleteFirst ? list[i].Obj1 : list[i + 1].Obj1; - var obj2 = deleteFirst ? list[i + 1].Obj2 : list[i].Obj2; - if (obj1 == null) { - obj1 = (T)(object)string.Empty; - } - if (obj2 == null) { - obj2 = (T)(object)string.Empty; + if (j + optCount < list.Count) { + // 只处理删1增1的情况 + while (i < j - 1) { + ret_list.Add(list[i]); + i++; } - var status = obj2.Equals(obj1) ? DiffStatus.Equal : DiffStatus.Modified; - if (status == DiffStatus.Modified) { - diffcount++; - // 超过一个修改,认为不应该优化,回退修改 - if (diffcount > 1) { - break; + + int oldi = i; + int diffcount = 0; + var test_list = new List>(); + while (i < j + optCount) { + var obj1 = deleteFirst ? list[i].Obj1 : list[i + 1].Obj1; + var obj2 = deleteFirst ? list[i + 1].Obj2 : list[i].Obj2; + if (obj1 == null) { + obj1 = (T)(object)string.Empty; } + if (obj2 == null) { + obj2 = (T)(object)string.Empty; + } + var status = obj2.Equals(obj1) ? DiffStatus.Equal : DiffStatus.Modified; + if (status == DiffStatus.Modified) { + diffcount++; + // 超过一个修改,认为不应该优化,回退修改 + if (diffcount > 1) { + break; + } + } + + test_list.Add(new DiffResult(obj1, obj2, status)); + i++; + } + if (diffcount <= 1) { + ret_list.AddRange(test_list); + //跳过最后一个优化掉的insert + i += 1; + } else { + i = oldi; } - - test_list.Add(new DiffResult(obj1, obj2, status)); - i++; - } - if (diffcount <= 1) { - ret_list.AddRange(test_list); - //跳过最后一个优化掉的insert - i += 1; - } else { - i = oldi; - } + } } + while (i < j) { ret_list.Add(list[i]); i++; diff --git a/ExcelMerge/Util.cs b/ExcelMerge/Util.cs index a51f1c0..78c8f1c 100644 --- a/ExcelMerge/Util.cs +++ b/ExcelMerge/Util.cs @@ -165,6 +165,18 @@ public static bool CopyCell(ICell oldCell, ICell newCell) { return true; } + + public static string NumberToExcelColumnId(int number) + { + StringBuilder sb = new StringBuilder(); + while (number > 0) + { + number--; + sb.Insert(0, (char)('A' + (number % 26))); + number /= 26; + } + return sb.ToString(); + } } public class Config { @@ -416,6 +428,8 @@ public class SheetDiffStatus { public Dictionary column2diff1 = new Dictionary(); public Dictionary column2diff2 = new Dictionary(); + public bool isConfigDiff = false; + public bool changed; } @@ -499,4 +513,5 @@ public class YamlDiffNode public List childs = new List(); } + } diff --git "a/test/\346\265\213\350\257\2251_1.xls" "b/test/\346\265\213\350\257\2251_1.xls" deleted file mode 100644 index aaf5cf139699b6e6d6571dea3e73c3c8da7e6ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17408 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 diff --git "a/test/\346\265\213\350\257\2251_2.xls" "b/test/\346\265\213\350\257\2251_2.xls" deleted file mode 100644 index 72c969a1892e83403c5b0763abce39c40a5bd4ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17920 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 diff --git "a/test/\346\265\213\350\257\225\345\210\206\351\241\2651.xlsx" "b/test/\346\265\213\350\257\225\345\210\206\351\241\2651.xlsx" index f281844f6b75d3c3b3e34af72a8b4753b08255d4..95946511fea3cca852274f90b0c856a910f7b631 100644 GIT binary patch delta 5257 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 delta 3917 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 delta 2972 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