在数据处理工作中,我们经常需要将一个包含多部门数据的总表按部门拆分成独立的工作表,或者将多个结构相同的工作表合并成一个总表。这种"拆分-合并"操作是Excel数据管理中的经典场景。本文将详细介绍如何使用Python和VBA实现这两种功能,并提供实用的代码示例。
一、业务场景与痛点分析
1.1 典型应用场景
场景一:月度工资表拆分
假设你是公司HR,每月需要处理全公司员工的工资数据。财务部门提供一个包含所有员工工资的总表,你需要:
按部门拆分成独立的工作表,分别发送给各部门负责人确认
各部门确认后,再将调整后的表格合并回总表
场景二:销售数据汇总分析
作为销售数据分析师,你需要:
将各区域提交的销售数据表合并成全国总表
从全国总表中按产品线拆分成不同的分析表
生成各产品线的独立分析报告
场景三:财务审计数据整理
在年度审计中,需要:
从总账中按科目拆分成明细表
将各子公司的报表合并成集团合并报表
按期间(月度/季度)拆分历史数据
1.2 传统手动操作的痛点
时间消耗巨大:1000行数据手动拆分可能需要1-2小时
容易出错:复制粘贴过程中可能遗漏行、错位数据
一致性难以保证:格式、公式、样式不统一
无法应对变化:部门调整、新增类别需要重新操作
缺乏可追溯性:操作过程没有日志,出错难以排查
二、Python实现详解
2.1 环境准备与库介绍
Python在数据处理方面有天然优势,主要使用以下库:
# 必需库安装# pip install pandas openpyxl xlrd xlwtimport pandas as pdimport numpy as npimport osfrom datetime import datetimeimport warningswarnings.filterwarnings('ignore')
2.2 按条件拆分工作表(高级版)
class ExcelSplitter: """Excel拆分器 - 高级功能版""" def __init__(self, file_path): """ 初始化拆分器 参数: file_path: Excel文件路径 """ self.file_path = file_path self.df = None self.split_info = {} def load_data(self, sheet_name=0, header=0): """ 加载Excel数据 参数: sheet_name: 工作表名或索引 header: 表头行索引 """ try: # 读取Excel文件 self.df = pd.read_excel( self.file_path, sheet_name=sheet_name, header=header, dtype=str # 先按字符串读取,避免类型问题 ) print(f"数据加载成功,共{len(self.df)}行,{len(self.df.columns)}列") return True except Exception as e: print(f"数据加载失败: {str(e)}") return False def split_by_column(self, split_column, output_path=None, keep_original_columns=True, add_summary=True): """ 按指定列拆分数据 参数: split_column: 拆分依据的列名 output_path: 输出文件路径 keep_original_columns: 是否保留所有原始列 add_summary: 是否添加汇总表 """ if self.df is None: print("请先加载数据") return False if split_column not in self.df.columns: print(f"列'{split_column}'不存在") print(f"可用列: {list(self.df.columns)}") return False # 设置输出路径 if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"拆分结果_{timestamp}.xlsx" # 获取唯一值 unique_values = self.df[split_column].dropna().unique() print(f"将按'{split_column}'拆分成{len(unique_values)}个分组") # 创建Excel写入器 with pd.ExcelWriter(output_path, engine='openpyxl') as writer: total_rows = 0 split_details = [] # 遍历每个分组 for i, value in enumerate(unique_values, 1): # 过滤数据 if pd.isna(value): group_df = self.df[self.df[split_column].isna()] sheet_name = "空值" else: group_df = self.df[self.df[split_column] == str(value)] # 处理工作表名称(Excel限制31字符,不能包含特殊字符) sheet_name = str(value)[:30] sheet_name = ''.join(c for c in sheet_name if c.isalnum() or c in (' ', '_', '-')) if len(group_df) == 0: continue # 是否保留所有列 if not keep_original_columns: group_df = group_df[[split_column]] # 写入工作表 try: group_df.to_excel( writer, sheet_name=sheet_name, index=False ) # 记录拆分信息 split_details.append({ '分组': value if not pd.isna(value) else '空值', '工作表名': sheet_name, '行数': len(group_df), '起始行': total_rows + 2, # Excel从1开始,标题占1行 '结束行': total_rows + len(group_df) + 1 }) total_rows += len(group_df) print(f" [{i}/{len(unique_values)}] 分组'{value}': {len(group_df)}行 -> 工作表'{sheet_name}'") except Exception as e: print(f" 写入分组'{value}'失败: {str(e)}") # 尝试使用备用名称 alt_sheet_name = f"Sheet_{i}" group_df.to_excel( writer, sheet_name=alt_sheet_name, index=False ) print(f" 已使用备用名称: {alt_sheet_name}") # 添加汇总表 if add_summary and split_details: summary_df = pd.DataFrame(split_details) summary_df = summary_df.sort_values('行数', ascending=False) # 计算占比 summary_df['占比'] = (summary_df['行数'] / summary_df['行数'].sum() * 100).round(2) summary_df['占比'] = summary_df['占比'].astype(str) + '%' summary_df.to_excel(writer, sheet_name='拆分汇总', index=False) # 添加总计行 total_row = pd.DataFrame([{ '分组': '总计', '工作表名': f'{len(split_details)}个表', '行数': total_rows, '起始行': '-', '结束行': '-', '占比': '100%' }]) total_row.to_excel(writer, sheet_name='拆分汇总', startrow=len(summary_df)+2, index=False, header=False) # 设置汇总表格式 workbook = writer.book worksheet = writer.sheets['拆分汇总'] # 设置列宽 for column in worksheet.columns: max_length = 0 column_letter = column[0].column_letter for cell in column: try: if len(str(cell.value)) > max_length: max_length = len(str(cell.value)) except: pass adjusted_width = min(max_length + 2, 50) worksheet.column_dimensions[column_letter].width = adjusted_width # 添加原始数据表(作为参考) self.df.to_excel(writer, sheet_name='原始数据', index=False) # 保存拆分信息 self.split_info = { 'split_column': split_column, 'output_file': output_path, 'total_groups': len(split_details), 'total_rows': total_rows, 'details': split_details } print(f"\n拆分完成!") print(f"输出文件: {output_path}") print(f"总分组数: {len(split_details)}") print(f"总数据行: {total_rows}") return output_path def split_by_multiple_columns(self, split_columns, output_path=None): """ 按多列组合拆分 参数: split_columns: 列名列表 output_path: 输出文件路径 """ if self.df is None: print("请先加载数据") return False # 创建组合列 combo_col = '拆分组合' self.df[combo_col] = self.df[split_columns].apply( lambda row: '_'.join([str(x) for x in row if pd.notna(x)]), axis=1 ) # 使用单列拆分方法 result = self.split_by_column(combo_col, output_path) # 删除临时列 self.df.drop(combo_col, axis=1, inplace=True) return result def split_with_conditions(self, conditions, output_path=None): """ 按条件表达式拆分 参数: conditions: 条件字典,格式为{'工作表名': '条件表达式'} output_path: 输出文件路径 """ if self.df is None: print("请先加载数据") return False if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"条件拆分_{timestamp}.xlsx" with pd.ExcelWriter(output_path, engine='openpyxl') as writer: remaining_df = self.df.copy() for sheet_name, condition in conditions.items(): try: # 使用eval计算条件 condition_df = remaining_df.query(condition) if len(condition_df) > 0: condition_df.to_excel(writer, sheet_name=sheet_name, index=False) print(f"条件'{condition}': {len(condition_df)}行 -> 工作表'{sheet_name}'") # 从剩余数据中移除 remaining_df = remaining_df.drop(condition_df.index) except Exception as e: print(f"处理条件'{condition}'失败: {str(e)}") # 剩余数据写入单独工作表 if len(remaining_df) > 0: remaining_df.to_excel(writer, sheet_name='其他数据', index=False) print(f"剩余数据: {len(remaining_df)}行 -> 工作表'其他数据'") return output_path# 使用示例if __name__ == "__main__": # 创建拆分器实例 splitter = ExcelSplitter("工资总表.xlsx") # 加载数据 if splitter.load_data(): # 按部门拆分 output_file = splitter.split_by_column( split_column="部门", output_path="按部门拆分.xlsx", add_summary=True ) # 多列组合拆分示例 # splitter.split_by_multiple_columns( # split_columns=["部门", "职级"], # output_path="按部门职级拆分.xlsx" # ) # 条件拆分示例 # conditions = { # "高工资": "月薪 >= 20000", # "中等工资": "月薪 >= 10000 and 月薪 < 20000", # "低工资": "月薪 < 10000" # } # splitter.split_with_conditions(conditions, "按工资拆分.xlsx")
2.3 合并多个工作表(高级版)
class ExcelMerger: """Excel合并器 - 高级功能版""" def __init__(self): self.merged_df = None self.merge_info = {} self.error_files = [] def merge_sheets_in_workbook(self, file_path, sheet_names=None, output_path=None, merge_method='vertical'): """ 合并工作簿中的多个工作表 参数: file_path: Excel文件路径 sheet_names: 要合并的工作表列表,None表示所有工作表 output_path: 输出文件路径 merge_method: 合并方式,'vertical'垂直合并,'horizontal'水平合并 """ try: # 读取Excel文件 excel_file = pd.ExcelFile(file_path) if sheet_names is None: sheet_names = excel_file.sheet_names df_list = [] sheet_details = [] for sheet_name in sheet_names: try: # 读取工作表 df = excel_file.parse(sheet_name) if len(df) > 0: # 添加来源信息 df['来源文件'] = os.path.basename(file_path) df['来源工作表'] = sheet_name df['读取时间'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") df_list.append(df) sheet_details.append({ '文件': os.path.basename(file_path), '工作表': sheet_name, '行数': len(df), '列数': len(df.columns) }) print(f" ✓ {sheet_name}: {len(df)}行, {len(df.columns)}列") else: print(f" ⚠ {sheet_name}: 空工作表") except Exception as e: print(f" ✗ {sheet_name}: 读取失败 - {str(e)}") if df_list: if merge_method == 'vertical': # 垂直合并(按行追加) # 统一列名 all_columns = set() for df in df_list: all_columns.update(df.columns) # 重新调整每个DataFrame的列 aligned_dfs = [] for df in df_list: # 添加缺失的列 for col in all_columns: if col not in df.columns: df[col] = np.nan # 按统一列序排列 df = df[list(all_columns)] aligned_dfs.append(df) self.merged_df = pd.concat(aligned_dfs, ignore_index=True) elif merge_method == 'horizontal': # 水平合并(按列合并) # 需要工作表有相同的行索引 aligned_dfs = [] for df in df_list: df = df.reset_index(drop=True) # 重命名列,避免重复 df.columns = [f"{sheet_name}_{col}" for col in df.columns] aligned_dfs.append(df) self.merged_df = pd.concat(aligned_dfs, axis=1) # 保存合并信息 self.merge_info = { 'input_file': file_path, 'total_sheets': len(df_list), 'total_rows': len(self.merged_df), 'total_columns': len(self.merged_df.columns), 'merge_method': merge_method, 'sheet_details': sheet_details } # 保存结果 if output_path: self._save_merged_data(output_path) return self.merged_df else: print("没有成功读取任何工作表") return None except Exception as e: print(f"合并失败: {str(e)}") return None def merge_multiple_workbooks(self, file_paths, sheet_name=0, output_path=None, add_source_info=True): """ 合并多个工作簿 参数: file_paths: 文件路径列表 sheet_name: 要合并的工作表名或索引 output_path: 输出文件路径 add_source_info: 是否添加来源信息 """ df_list = [] file_details = [] self.error_files = [] print(f"开始合并{len(file_paths)}个文件...") print("=" * 60) for i, file_path in enumerate(file_paths, 1): print(f"[{i}/{len(file_paths)}] 处理: {os.path.basename(file_path)}") try: # 读取Excel文件 if isinstance(sheet_name, int): # 按索引读取 df = pd.read_excel(file_path, sheet_name=sheet_name) else: # 按名称读取 df = pd.read_excel(file_path, sheet_name=sheet_name) if len(df) > 0: # 添加来源信息 if add_source_info: df['来源文件'] = os.path.basename(file_path) df['文件路径'] = file_path df['文件大小(MB)'] = os.path.getsize(file_path) / (1024 * 1024) df['修改时间'] = datetime.fromtimestamp( os.path.getmtime(file_path) ).strftime("%Y-%m-%d %H:%M:%S") df_list.append(df) file_details.append({ '序号': i, '文件名': os.path.basename(file_path), '行数': len(df), '列数': len(df.columns), '文件大小(MB)': round(os.path.getsize(file_path) / (1024 * 1024), 2), '状态': '成功' }) print(f" ✓ 成功读取: {len(df)}行, {len(df.columns)}列") else: file_details.append({ '序号': i, '文件名': os.path.basename(file_path), '行数': 0, '列数': 0, '文件大小(MB)': round(os.path.getsize(file_path) / (1024 * 1024), 2), '状态': '空文件' }) print(f" ⚠ 空文件") except Exception as e: error_msg = str(e) self.error_files.append({ 'file': file_path, 'error': error_msg }) file_details.append({ '序号': i, '文件名': os.path.basename(file_path), '行数': 0, '列数': 0, '文件大小(MB)': round(os.path.getsize(file_path) / (1024 * 1024), 2) if os.path.exists(file_path) else 0, '状态': f'失败: {error_msg[:30]}...' }) print(f" ✗ 读取失败: {error_msg}") print("-" * 60) if df_list: # 合并所有DataFrame self.merged_df = pd.concat(df_list, ignore_index=True) # 保存合并信息 self.merge_info = { 'total_files': len(file_paths), 'success_files': len(df_list), 'error_files': len(self.error_files), 'total_rows': len(self.merged_df), 'total_columns': len(self.merged_df.columns), 'file_details': file_details } # 保存结果 if output_path: self._save_merged_data(output_path, include_summary=True) print("\n" + "=" * 60) print("合并完成!") print(f"成功合并: {len(df_list)}/{len(file_paths)} 个文件") print(f"总数据行: {len(self.merged_df)}") print(f"总数据列: {len(self.merged_df.columns)}") if self.error_files: print(f"失败文件: {len(self.error_files)} 个") for error in self.error_files[:3]: # 显示前3个错误 print(f" - {os.path.basename(error['file'])}: {error['error'][:50]}") return self.merged_df else: print("没有成功读取任何文件") return None def _save_merged_data(self, output_path, include_summary=True): """保存合并后的数据""" if self.merged_df is None: print("没有数据可保存") return False with pd.ExcelWriter(output_path, engine='openpyxl') as writer: # 保存合并数据 self.merged_df.to_excel( writer, sheet_name='合并数据', index=False ) # 添加汇总信息 if include_summary and self.merge_info.get('file_details'): summary_df = pd.DataFrame(self.merge_info['file_details']) summary_df.to_excel(writer, sheet_name='合并汇总', index=False) # 添加错误信息 if self.error_files: error_df = pd.DataFrame(self.error_files) error_df['file'] = error_df['file'].apply(os.path.basename) error_df.to_excel(writer, sheet_name='错误文件', index=False) # 添加数据统计 stats_data = { '统计项': ['总文件数', '成功文件数', '失败文件数', '总行数', '总列数', '生成时间'], '数值': [ self.merge_info.get('total_files', 0), self.merge_info.get('success_files', 0), len(self.error_files), len(self.merged_df), len(self.merged_df.columns), datetime.now().strftime("%Y-%m-%d %H:%M:%S") ] } stats_df = pd.DataFrame(stats_data) stats_df.to_excel(writer, sheet_name='数据统计', index=False) print(f"结果已保存: {output_path}") return True def merge_with_data_cleaning(self, file_paths, cleaning_rules=None): """ 合并时进行数据清洗 参数: file_paths: 文件路径列表 cleaning_rules: 清洗规则字典 """ # 先合并数据 df = self.merge_multiple_workbooks(file_paths, add_source_info=True) if df is None: return None # 应用清洗规则 if cleaning_rules: print("\n应用数据清洗规则...") for col, rules in cleaning_rules.items(): if col in df.columns: original_count = len(df) # 去重 if rules.get('remove_duplicates'): df = df.drop_duplicates(subset=rules['remove_duplicates']) print(f" {col}: 去重,移除{original_count - len(df)}行") # 处理缺失值 if rules.get('fillna'): fill_value = rules['fillna'] df[col] = df[col].fillna(fill_value) print(f" {col}: 填充缺失值") # 去除空格 if rules.get('strip'): df[col] = df[col].astype(str).str.strip() print(f" {col}: 去除首尾空格") # 类型转换 if rules.get('dtype'): target_type = rules['dtype'] try: df[col] = df[col].astype(target_type) print(f" {col}: 转换为{target_type}类型") except: print(f" {col}: 类型转换失败") return df# 使用示例if __name__ == "__main__": # 创建合并器实例 merger = ExcelMerger() # 合并多个工作簿 import glob excel_files = glob.glob("各区域销售数据/*.xlsx") if excel_files: # 定义数据清洗规则 cleaning_rules = { '销售额': { 'fillna': 0, 'dtype': 'float' }, '客户名称': { 'strip': True }, '订单号': { 'remove_duplicates': ['订单号'] } } # 合并并清洗数据 merged_data = merger.merge_with_data_cleaning( file_paths=excel_files, cleaning_rules=cleaning_rules ) if merged_data is not None: # 保存结果 merger._save_merged_data("合并结果_已清洗.xlsx") else: print("未找到Excel文件")
三、VBA实现详解
3.1 工作表拆分(完整版)
' 标准模块:ExcelSplitterOption Explicit' 拆分配置类型Type SplitConfig SourceSheet As String SplitColumn As String OutputPath As String KeepFormatting As Boolean AddSummary As Boolean CreateNewWorkbook As BooleanEnd TypeSub SplitWorksheetByColumn() ' 主过程:按列拆分工作表 Dim config As SplitConfig Dim result As Boolean ' 获取用户配置 If Not GetSplitConfigFromUser(config) Then MsgBox "操作已取消", vbInformation Exit Sub End If ' 执行拆分 result = ExecuteSplit(config) ' 显示结果 If result Then MsgBox "工作表拆分完成!", vbInformation Else MsgBox "拆分过程中出现错误", vbExclamation End IfEnd SubFunction GetSplitConfigFromUser(ByRef config As SplitConfig) As Boolean ' 获取用户配置(简化版,实际中可使用用户窗体) ' 设置默认值 config.SourceSheet = ActiveSheet.Name config.SplitColumn = "" config.OutputPath = ThisWorkbook.Path & "\拆分结果_" & Format(Now, "yyyymmdd_hhmmss") & ".xlsx" config.KeepFormatting = True config.AddSummary = True config.CreateNewWorkbook = True ' 显示输入框获取拆分列 Dim inputColumn As String inputColumn = InputBox("请输入拆分依据的列名(如:部门、地区等)", "拆分设置", "部门") If inputColumn = "" Then GetSplitConfigFromUser = False Exit Function End If config.SplitColumn = Trim(inputColumn) GetSplitConfigFromUser = TrueEnd FunctionFunction ExecuteSplit(config As SplitConfig) As Boolean ' 执行拆分操作 On Error GoTo ErrorHandler Dim sourceWs As Worksheet Dim newWb As Workbook Dim splitDict As Object Dim lastRow As Long, lastCol As Long Dim splitRange As Range Dim cell As Range Dim key As Variant Dim itemCount As Long Dim summaryData() As Variant Dim i As Long ' 设置源工作表 Set sourceWs = ThisWorkbook.Worksheets(config.SourceSheet) ' 获取数据范围 lastRow = sourceWs.Cells(sourceWs.Rows.Count, 1).End(xlUp).Row lastCol = sourceWs.Cells(1, sourceWs.Columns.Count).End(xlToLeft).Column ' 查找拆分列 Dim splitColIndex As Long splitColIndex = 0 For i = 1 To lastCol If sourceWs.Cells(1, i).Value = config.SplitColumn Then splitColIndex = i Exit For End If Next i If splitColIndex = 0 Then MsgBox "未找到列: " & config.SplitColumn, vbExclamation ExecuteSplit = False Exit Function End If ' 创建字典存储分组信息 Set splitDict = CreateObject("Scripting.Dictionary") ' 收集分组信息 For i = 2 To lastRow key = sourceWs.Cells(i, splitColIndex).Value If Len(Trim(CStr(key))) > 0 Then If Not splitDict.Exists(key) Then splitDict.Add key, New Collection End If splitDict(key).Add i End If Next i ' 创建新工作簿 If config.CreateNewWorkbook Then Set newWb = Workbooks.Add Else ' 在当前工作簿中操作 Set newWb = ThisWorkbook End If ' 禁用更新以提高性能 Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Application.DisplayAlerts = False ' 准备汇总数据 ReDim summaryData(1 To splitDict.Count + 2, 1 To 4) summaryData(1, 1) = "分组" summaryData(1, 2) = "工作表名" summaryData(1, 3) = "行数" summaryData(1, 4) = "占比" ' 复制每个分组到新工作表 i = 1 For Each key In splitDict.Keys Dim newWs As Worksheet Dim rowCollection As Collection Dim destRow As Long Dim srcRow As Long ' 创建工作表 Set newWs = newWb.Worksheets.Add(After:=newWb.Worksheets(newWb.Worksheets.Count)) ' 处理工作表名称(Excel限制) Dim sheetName As String sheetName = CStr(key) If Len(sheetName) > 31 Then sheetName = Left(sheetName, 31) End If ' 移除无效字符 sheetName = CleanSheetName(sheetName) newWs.Name = sheetName ' 复制标题行 sourceWs.Range(sourceWs.Cells(1, 1), sourceWs.Cells(1, lastCol)).Copy newWs.Cells(1, 1).PasteSpecial Paste:=xlPasteAll ' 复制数据行 Set rowCollection = splitDict(key) destRow = 2 For Each srcRow In rowCollection sourceWs.Range(sourceWs.Cells(srcRow, 1), sourceWs.Cells(srcRow, lastCol)).Copy newWs.Cells(destRow, 1).PasteSpecial Paste:=xlPasteAll destRow = destRow + 1 Next srcRow ' 记录汇总信息 summaryData(i + 1, 1) = key summaryData(i + 1, 2) = sheetName summaryData(i + 1, 3) = rowCollection.Count summaryData(i + 1, 4) = Format(rowCollection.Count / (lastRow - 1) * 100, "0.00") & "%" i = i + 1 Next key ' 添加汇总表 If config.AddSummary Then Dim summaryWs As Worksheet Set summaryWs = newWb.Worksheets.Add(Before:=newWb.Worksheets(1)) summaryWs.Name = "拆分汇总" ' 写入汇总数据 summaryWs.Range("A1").Resize(UBound(summaryData, 1), UBound(summaryData, 2)).Value = summaryData ' 添加总计行 Dim totalRow As Long totalRow = UBound(summaryData, 1) + 1 summaryWs.Cells(totalRow, 1).Value = "总计" summaryWs.Cells(totalRow, 2).Value = splitDict.Count & "个表" summaryWs.Cells(totalRow, 3).Value = lastRow - 1 summaryWs.Cells(totalRow, 4).Value = "100%" ' 格式化汇总表 With summaryWs ' 设置列宽 .Columns("A:D").AutoFit ' 设置标题格式 With .Range("A1:D1") .Font.Bold = True .Interior.Color = RGB(200, 200, 200) .HorizontalAlignment = xlCenter End With ' 设置总计行格式 With .Rows(totalRow) .Font.Bold = True .Interior.Color = RGB(220, 230, 240) End With ' 添加边框 .Range("A1:D" & totalRow).Borders.LineStyle = xlContinuous End With End If ' 保存工作簿 If config.CreateNewWorkbook Then newWb.SaveAs config.OutputPath newWb.Close SaveChanges:=True End If ' 恢复设置 Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomatic Application.DisplayAlerts = True ExecuteSplit = True Exit FunctionErrorHandler: ' 错误处理 Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomatic Application.DisplayAlerts = True MsgBox "拆分过程中发生错误:" & vbCrLf & Err.Description, vbCritical ExecuteSplit = FalseEnd FunctionFunction CleanSheetName(sheetName As String) As String ' 清理工作表名称,移除无效字符 Dim invalidChars As String Dim i As Long Dim result As String invalidChars = ":\/?*[]" result = sheetName For i = 1 To Len(invalidChars) result = Replace(result, Mid(invalidChars, i, 1), "_") Next i ' 不能以单引号开始或结束 If Left(result, 1) = "'" Then result = Mid(result, 2) End If If Right(result, 1) = "'" Then result = Left(result, Len(result) - 1) End If CleanSheetName = resultEnd Function
