总是听到或看到有人问,编程好学吗?如何入门?多久能学会?它能做些什么?怎么写代码呀?执行过程中出问题了谁能帮帮我...如果你也有类似的问题那就赶快关注我的公众号,一起学起来吧!
友情提示:本期分享的内容涉及范围非常广,代码量非常庞大,是想突飞猛进地学习编程知识,还是只想要个趁手的自动化工具,请大家根据自己实际情况合理利用

需求描述
在使用Excel处理各类表格数据时,拆分操作使用频度还是很高的。尤其是在处理数据量较大的表格,或者需要对数据进行分门别类管理时,掌握高效的拆分方法就显得尤为重要
比如以下一份Excel文档,包含很多个工作表,每个工作表内容和格式也不尽相同(表头、行/列数、样式等)。除此之外,按哪一列数据内容进行拆分也不固定
样例1:表头占用1行,按照B列内容拆分

样例2:表头占用3行,按照A列内容拆分

当然,还有很多种类型表格,不再一一举例。若希望仅编写一套代码就能覆盖上述所有应用场景,那么就要求我们在编写功能函数前,就必须将通用性和扩展性作为核心设计原则
这意味着函数需要抽象出各类表格处理的共性逻辑,并预留足够的接口,以便未来能够轻松适配新的、未预见到的表格类型或数据格式,从而实现“一次编写,多处适用”的目标
友情提醒:想要设计兼具通用性与扩展性的功能函数,被广泛认为是编程者面临的最困难挑战之一,这里的困难并非技术本身,而是来自于对“未来”的预测、对“本质”的抽象。对编程感兴趣的朋友可以从这一方便面入手继续挑战

代码及使用说明
将文中提供的代码全部复制粘贴到标准模块后,每当需要拆分工作表数据时,只需传入正确的参数调用 SplitWorksheetByColumn (主拆分功能函数),即可像调用 VBA 内置函数那样简便地执行拆分操作
如何正确地传递参数呢?就要简单了解SplitWorksheetByColumn的语法知识,它有5个参数,从左到右依次为:
sourceSheet: 源工作表对象
splitColumn: 拆分依据的列号,为数值类型,如A列为1,B列为2......
headerRows: 表头行数,为数值类型,如表头占用3行就输入3
outputType: 输出类型,目前代码中只有“工作簿”这一种类型,后续可扩展
outputPath: 输出路径(仅当outputType="工作簿"时需要),缺省则会默认源工作表对应的Excel文档路径
调用举例:这一行代码的意思是将变量ws对应的工作表(表头占3行),按照A列拆分成独立的Excel文档,并保存到路径“D:\常用文件”下
SplitWorksheetByColumn(ws, 1, 3, "工作簿", "D:\常用文件")拆分前:按照A列数据进行拆分,3行表头

拆分后路径下的Excel文档显示


当然,我们还可以结合上一期内容【Excel VBA编程】使用Userform界面选择工作表,告别硬编码,通过界面获取待拆分工作表、拆分列和表头行数,实现整个拆分过程全自动化
2.2 参考代码
主拆分功能函数: 按指定列拆分工作表数据
Public Function SplitWorksheetByColumn( _ByVal sourceSheet As Worksheet, _ByVal splitColumn As Integer, _ByVal headerRows As Integer, _ByVal outputType As String, _Optional ByVal outputPath As String = "" _) As BooleanOn Error GoTo ErrorHandler' 参数验证If sourceSheet Is Nothing ThenMsgBox "源工作表不能为空", vbExclamationExit FunctionEnd IfIf splitColumn < 1 Or splitColumn > sourceSheet.UsedRange.Columns.Count ThenMsgBox "拆分列号超出有效范围", vbExclamationExit FunctionEnd If' 设置Application.ScreenUpdating = FalseApplication.Calculation = xlCalculationManualApplication.DisplayAlerts = False' 获取唯一值字典Dim dict As ObjectSet dict = GetUniqueValuesDictionary(sourceSheet, splitColumn, headerRows) '调用子过程' 根据输出类型执行不同拆分逻辑Select Case LCase(outputType)Case "工作表"'预留接口,后续补充Case "工作簿"If outputPath = "" Then outputPath = ThisWorkbook.Path & "\拆分结果"SplitToWorkbooks sourceSheet, dict, splitColumn, headerRows, outputPath & "\拆分结果"Case ElseMsgBox "不支持的输出类型:" & outputType, vbExclamationExit FunctionEnd SelectSplitWorksheetByColumn = TrueGoTo CleanUpErrorHandler:MsgBox "拆分过程中发生错误:" & Err.Description, vbCriticalSplitWorksheetByColumn = FalseCleanUp:' 恢复设置Application.ScreenUpdating = TrueApplication.Calculation = xlCalculationAutomaticApplication.DisplayAlerts = True' 释放资源Set dict = NothingEnd Function
辅助功能函数:拆分列数据处理
Private Function GetUniqueValuesDictionary( _ByVal sourceSheet As Worksheet, _ByVal splitColumn As Integer, _ByVal headerRows As Integer _) As ObjectDim dict As ObjectSet dict = CreateObject("Scripting.Dictionary")Dim lastRow As LonglastRow = sourceSheet.Cells(sourceSheet.Rows.Count, splitColumn).End(xlUp).RowDim i As LongFor i = headerRows + 1 To lastRowDim keyValue As VariantkeyValue = sourceSheet.Cells(i, splitColumn).Value' 跳过空值If Not IsEmpty(keyValue) And keyValue <> "" Then' 使用字典收集行范围If Not dict.Exists(keyValue) Then' 新键值:创建行集合Set dict(keyValue) = sourceSheet.Rows(i)Else' 已有键值:合并行Set dict(keyValue) = Union(dict(keyValue), sourceSheet.Rows(i))End IfEnd IfNext iSet GetUniqueValuesDictionary = dictEnd Function
辅助功能函数:输出独立的Excel文件
Private Sub SplitToWorkbooks( _ByVal sourceSheet As Worksheet, _ByVal dict As Object, _ByVal splitColumn As Integer, _ByVal headerRows As Integer, _ByVal outputPath As String _)' 创建输出文件夹Dim fso As ObjectSet fso = CreateObject("Scripting.FileSystemObject")If Not fso.FolderExists(outputPath) Thenfso.CreateFolder outputPathEnd IfDim keys As Variant, items As Variantkeys = dict.keysitems = dict.itemsDim i As LongFor i = 0 To dict.Count - 1' 创建新工作簿Dim newWorkbook As WorkbookSet newWorkbook = Workbooks.AddDim newSheet As WorksheetSet newSheet = newWorkbook.Worksheets(1)newSheet.Name = "数据"' 复制表头和数据With newSheetsourceSheet.Rows("1:" & headerRows).Copy.Range("A1").PasteSpecial Paste:=xlPasteColumnWidths '复制列宽Application.CutCopyMode = False ' 清除剪贴板' 复制表头sourceSheet.Rows("1:" & headerRows).Copy Destination:=.Range("A1")' 复制数据items(i).Copy .Range("A" & headerRows + 1)End WithApplication.CutCopyMode = False' 保存文件Dim fileName As StringfileName = CStr(keys(i)) & ".xlsx"newWorkbook.SaveAs fileName:=outputPath & "\" & fileName, _FileFormat:=xlOpenXMLWorkbooknewWorkbook.Close SaveChanges:=FalseNext iSet fso = NothingEnd Sub

结束语
专注于单一、特定场景的“纯功能实现”代码量小、开发速度快,但是需要频繁地修改参数以适配更多的场合。若是要考虑更多的适用场景就会让代码量变大,逻辑也越来越复杂。即便是如此,还是会出现异常情况而无法达到预期。因此想要开发一款完美的自动化工具真的是非常耗费时间和精力。此时,就需要考量和权衡:到底是功能优先还是通用性优先
好了,今天的分享到此结束了,咱们下期继续
本公众号一直在不间断地分享免费的编程案例和实用技巧。无论您是用来提升自动化办公效率还是想提升自我,请关注我的公众号,解锁更多的编程知识