如何测试Excel文件中的任何非标题单元格是否为粗体或斜体

发布于 2024-09-08 05:56:27 字数 484 浏览 7 评论 0原文

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

编辑:我只是对这个问题给予奖励,因为我正在寻找完整的 C# 示例,如果您认为我的问题不明确,请提出问题。

We use an Excel sheet which contains some business logic (and so it is often edited by non-IT). Some C++ code is generated in VBA from the same sheet - silly, I know. I plan to write a bunch of unit tests against this worksheet, ensuring strict format for the benefit of all. For instance, things should be sorted alphabetically. I have not done this sort of work before; not even sure which library to use. To get my feet wet, I would like to find all cells which have font other than "automatic color, plain style, Arial, size 10" - e.g. red or bold or size 11, or ComicSans font. Then I want to check if those cells are "non-header" cells. The "header" cells are those which are part of known named ranges. For instance, if such cell does belong to a named range "XYZheaders", then it is Ok. If not, then I wish to report the coordinates of a cell (ideally as something human-readable like "D25" for every cell which has a problem, as well as indicate whether the problem is with color, font type, style, or size.

EDIT: I just put bounty on this question because I am looking for a complete C# sample. Please do ask questions if you think that my question is ambiguous.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

贩梦商人 2024-09-15 05:56:27

这是我的解决方案。我已经使用一些 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 文件的名称作为其第一个参数。该文件被打开,每个单元格都根据不同的字体标准进行测试。具有“非默认字体”的单元格将根据命名范围进行测试,超出这些范围的单元格将输出到控制台。

像往常一样,应该在程序中添加一些错误处理 - 但希望这可以帮助您开始。

Here is my solution. I've tested it with some Excel 2007 files (.xlsx). The program can be built using VS 2010 (targeting .NET 4) with the following four references: Microsoft.CSharp, Microsoft.Office.Interop.Excel, System and System.Core.

Using .NET 4 makes it a bit easier to work with Excel.

Anyway here's the code:

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));
        }
    }
}

The program assumes the name of an excel-file as its first argument. This file is opened and each cell is tested against different font-criteria. The cells with "non-default-font" is tested against the named ranged, and those that fall outside of these ranges are output to the console.

As usual some errorhandling should be added to the program - but hopefully this should get you started.

七分※倦醒 2024-09-15 05:56:27

这应该可以解决问题,享受吧。请记住,放入新的范围名称不会触发包含此函数的单元格的重新计算(因此在创建范围名称后按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

This should do the trick, enjoy. Keep in mind that putting in new Range Names will not trigger a recalc of a cell containing this function (so hit F9 after creating range names).

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文