【问题标题】:How to test whether any non-header cell in Excel file is bold or italic如何测试Excel文件中的任何非标题单元格是粗体还是斜体
【发布时间】:2010-07-06 16:41:07
【问题描述】:

我们使用包含一些业务逻辑的 Excel 工作表(因此通常由非 IT 人员编辑)。一些 C++ 代码是在 VBA 中从同一张表中生成的——我知道这很傻。我计划针对这个工作表编写一堆单元测试,确保严格的格式以造福所有人。例如,事物应该按字母顺序排序。我以前没有做过这种工作;甚至不确定要使用哪个库。为了让我的脚湿透,我想找到所有具有“自动颜色,纯样式,Arial,10号”以外字体的单元格 - 例如红色或粗体或大小 11,或 ComicSans 字体。然后我想检查这些单元格是否是“非标题”单元格。 “标题”单元格是已知命名范围的一部分。例如,如果这样的单元格确实属于命名范围“XYZheaders”,那么就可以了。如果不是,那么我希望报告一个单元格的坐标(理想情况下,对于每个有问题的单元格来说,像“D25”这样的人类可读的东西,并指出问题是否与颜色、字体类型、样式或大小有关.

编辑:我只是悬赏这个问题,因为我正在寻找一个完整的 C# 示例。如果您认为我的问题模棱两可,请提出问题。

【问题讨论】:

    标签: c# unit-testing excel named-ranges


    【解决方案1】:

    这是我的解决方案。我已经用一些 Excel 2007 文件 (.xlsx) 对其进行了测试。该程序可以使用 VS 2010(针对 .NET 4)构建,具有以下四个参考:Microsoft.CSharp、Microsoft.Office.Interop.Excel、System 和 System.Core。

    使用 .NET 4 可以更轻松地使用 Excel。

    代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Excel = Microsoft.Office.Interop.Excel;
    
    namespace ExcelTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                Excel.Application excelapplication = null;
                Excel.Workbook workbook = null;
    
                try
                {
                    excelapplication = new Excel.Application();
                    workbook = excelapplication.Workbooks.Open(args[0]);
                    var errors = new Dictionary<string, List<string>>();
                    foreach (Excel.Worksheet sheet in workbook.Sheets)
                    {
                        int rowCount = sheet.UsedRange.Cells.Rows.Count;
                        int colCount = sheet.UsedRange.Cells.Columns.Count;
                        var usedCells = sheet.UsedRange.Cells;
    
                        for (int i = 1; i <= rowCount; i++)
                        {
                            for (int j = 1; j <= colCount; j++)
                            {
                                Excel.Range range = usedCells[i, j];
                                List<string> cellErrors;
                                if (HasNonDefaultFont(range, out cellErrors))
                                {
                                    if (!IsHeaderCell(workbook, range))
                                    {
                                        string cellDisplayTitle = String.Format("{0}!{1}", sheet.Name, range.Address);
                                        errors[cellDisplayTitle] = cellErrors;
                                    }
                                }
                            }
                        }
                    }
                    ReportErrors(errors);
                }
                finally
                {
                    if (workbook != null)
                        workbook.Close();
                    if (excelapplication != null)
                        excelapplication.Quit();
                }
            }
    
            static bool HasNonDefaultFont(Excel.Range range, out List<string> differences)
            {
                differences = new List<string>();
    
                if (range.Font.Color != 0.0)
                    differences.Add("Has font-color");
    
                if (range.Font.Bold)
                    differences.Add("Is bold");
    
                if (range.Font.Italic)
                    differences.Add("Is italic");
    
                if (range.Font.Underline != (int)Microsoft.Office.Interop.Excel.XlUnderlineStyle.xlUnderlineStyleNone)
                    differences.Add("Is underline");
    
                if (range.Font.Strikethrough)
                    differences.Add("Is strikethrough");
    
                if (range.Font.Name != "Arial")
                    differences.Add(String.Format("Font is {0}", range.Font.Name));
    
                if (range.Font.Size != 10)
                    differences.Add(String.Format("Font size is {0}", range.Font.Size));
    
                return differences.Count != 0;
            }
    
            static bool IsHeaderCell(Excel.Workbook workbook, Excel.Range range)
            {
                // Look through workbook names:
                foreach (Excel.Name namedRange in workbook.Names)
                {
                    if (range.Parent == namedRange.RefersToRange.Parent && range.Application.Intersect(range, namedRange.RefersToRange) != null)
                        return true;
                }
    
                // Look through worksheet-names.
                foreach (Excel.Name namedRange in range.Worksheet.Names)
                {
                    if (range.Parent == namedRange.RefersToRange.Parent && range.Worksheet.Application.Intersect(range, namedRange.RefersToRange) != null)
                        return true;
                }
                return false;
            }
    
            static void ReportErrors(Dictionary<string, List<string>> errors)
            {
                if (errors.Count > 0)
                {
                    Console.WriteLine("Found the following errors:");
                    Console.WriteLine("---------------------------------");
                    Console.WriteLine("{0,-15} | Error", "Cell");
                    Console.WriteLine("---------------------------------");
                }
    
                foreach (KeyValuePair<string, List<string>> kv in errors)
                    Console.WriteLine("{0,-15} | {1}", kv.Key, kv.Value.Aggregate((e, s) => e + ", " + s));
            }
        }
    }
    

    程序假定 excel 文件的名称作为其第一个参数。打开此文件,并针对不同的字体标准测试每个单元格。具有“非默认字体”的单元格将针对命名范围进行测试,超出这些范围的单元格将输出到控制台。

    像往常一样,应该在程序中添加一些错误处理 - 但希望这能让你开始。

    【讨论】:

      【解决方案2】:

      这应该可以解决问题,享受吧。请记住,输入新的范围名称不会触发包含此函数的单元格的重新计算(因此在创建范围名称后按 F9)。

      Option Explicit
      
      Public Function IsDataCellBoldOrItalic() As Boolean
          Dim rngName As Name
          Dim intersectRange As Name
      
          For Each rngName In ActiveWorkbook.Names
              If Not Intersect(rngName.RefersToRange, Application.ThisCell) Is Nothing Then
                  IsDataCellBoldOrItalic = False
                  Exit Function
              End If
          Next
      
          ''# Now we know we are not in a "header" cell
          IsDataCellBoldOrItalic = Application.ThisCell.Font.Bold Or Application.ThisCell.Font.Italic
      
      End Function
      

      【讨论】:

      • 酷,这很普通VB.Net 对吧?我想我可以很容易地把它翻译成C#
      • @Hamish:看起来这是您可以在工作簿中运行的 VBA。
      • 嗯...我想我可以使用它,但我更喜欢加载和分析 Excel 文件的 C# 代码。
      • @Hamish:哦,对不起,我误解了你想要 VBA。是的,实际上并没有任何隐藏的技巧可以转换为 C#,除了您期望的一堆属性仅作为 'get_' 方法存在。例如,您不会找到 Workbook.Names 属性,但会找到 Workbook.get_Names() 方法。
      • 仅供参考:我悬赏以获得完整的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      相关资源
      最近更新 更多