【问题标题】:Excel Adding WorksheetsExcel 添加工作表
【发布时间】:2016-05-25 01:54:40
【问题描述】:

我需要创建一个子目录,以便根据名为 AllCities 的工作表中的名称列表创建工作表。城市名称列表从单元格 A2 开始。工作表需要以列表中的单元格值命名,并且不应创建任何重复的工作表。这是我目前所拥有的:

Sub addsheets()
Dim myCell As Range
Dim Cities As Range


With Sheets("AllCities")
Set Cities = Sheets("AllCities").Range("A2")
Set Cities = Range(Cities, Cities.End(xlDown))
End With

For Each myCell In Cities
If Not myCell.Value = vbNullString Then
    Sheets.Add After:=Sheets(Sheets.Count)
    Sheets(Sheets.Count).Name = myCell.Value
End If
Next myCell

End Sub

【问题讨论】:

  • 那么你的问题是什么?
  • 您能否给出任何至少赞赏所有这些(风向标)努力的亲切迹象?

标签: vba excel


【解决方案1】:

看起来问题在于确保不创建重复项。我可以想到两种方法来做到这一点,但我选择了我认为对这种情况最有效的方法。

  1. 记住名称(已选择)- 记住可以非常快速检查的字符串中的工作表名称,如果您有数千个大型(长度超过 25 个)城市名称,这将不是最佳解决方案选项卡,但我怀疑你会有不同的问题需要考虑。
  2. 创建一个执行检查的错误处理过程 - 您可以调用第二个过程来检查工作表是否存在,这会缩短处理时间,但如果在大型设备上使用会更安全规模。

以下是包含重复检查的代码。

Sub addsheets()
Dim myCell      As Range
Dim Cities      As Range
Dim StrSheets   As String
Dim WkSht       As Excel.Worksheet

With ThisWorkbook.Worksheets("AllCities")
    Set Cities = Range(.Range("A2"), .Range("A2").End(xlDown))
End With

StrSheets = "|"
For Each WkSht In ThisWorkbook.Worksheets
    StrSheets = StrSheets & WkSht.Name & "|"
Next

For Each myCell In Cities
    If Not myCell.Value = vbNullString Then
        If InStr(1, StrSheets, "|" & myCell.Value & "|") = 0 Then
            Sheets.Add After:=Sheets(Sheets.Count)
            Sheets(Sheets.Count).Name = myCell.Value
            StrSheets = StrSheets & myCell.Value & "|"
        End If
    End If
Next myCell

End Sub

【讨论】:

  • 这是尽可能使用和修改OP代码的好方法。效果很好。
【解决方案2】:

如果您不想要任何重复项,那么对您来说最好的办法就是删除重复项。如果您希望原始工作表保持不变,请创建工作表的副本,然后删除重复项并创建工作表。

【讨论】:

    【解决方案3】:

    实际上利用Range对象的RemoveDuplicates()方法会问这个问题:

    Option Explicit
    
    Sub AddSheets()
        Dim myCell As Range
        Dim Cities As Range
    
        With Sheets("AllCities")
            Set Cities = .Range("A2", .Cells(.Rows.Count, "A").End(xlUp)).SpecialCells(xlCellTypeConstants) '<~~ consider non blank cells of column "A" from cell "A2" down to last non blank cell
            Cities.RemoveDuplicates Columns:=Array(1), Header:=xlNo '<~~ remove duplicates
        End With
    
        For Each myCell In Cities
            Sheets.Add After:=Sheets(Sheets.Count)
            ActiveSheet.Name = myCell.Value
        Next myCell
    
    End Sub
    

    只要您不在乎所有重复值都会永远丢失!

    但它会留下两个未处理的重要例外:

    1) 在宏执行之前已经存在的工作表的重复名称

    2) 工作表名称中的无效字符

    您可以处理那些具有专用功能的功能,这些功能将为后续步骤开绿灯,如下所示:

    Option Explicit
    
    Sub AddSheets()
        Dim myCell As Range
        Dim Cities As Range
    
        With Sheets("AllCities")
            Set Cities = .Range("A2", .Cells(.Rows.Count, "A").End(xlUp)).SpecialCells(xlCellTypeConstants) '<~~ consider non blank cells of column "A" from cell "A2" down to last non blank cell
            Cities.RemoveDuplicates Columns:=Array(1), Header:=xlNo '<~~ remove duplicates from list
        End With
    
        For Each myCell In Cities
            If CheckSheetName(myCell.Value) Then '<~~ check for invalid sheet name...
                If CheckSheetDuplicate(ActiveWorkbook, myCell.Value) Then '<~~ ... if valid name then check for duplicates in existent sheets...
                    Sheets.Add After:=Sheets(Sheets.Count) '<~~ ... if no duplicates sheets then finally add a new sheet...
                    ActiveSheet.Name = myCell.Value'<~~ ... and give it proper name
                End If
            End If
        Next myCell
    
    End Sub
    
    
    Function CheckSheetName(shtName As String) As Boolean
        Dim invalidChars As Variant
        Dim myChar As Variant
    
        invalidChars = Array(":", "/", "\", "?", "*", "[", "]")
    
         'check shtName for forbidden characters
        CheckSheetName = True
        For Each myChar In invalidChars
            If InStr(shtName, myChar) > 0 Then
                CheckSheetName = False
                Exit For
            End If
        Next myChar
    End Function
    
    Function CheckSheetDuplicate(wb As Workbook, shtName As String) As Boolean
        CheckSheetDuplicate = True '<~~ set positive check result. it'll be turned to negative in case of problems ..
        On Error Resume Next
        CheckSheetDuplicate = wb.Sheets(shtName) Is Nothing '<~~ set negative check result in case of problems from any attempt to use a sheet with given name:  for instance trying and use it as an object
    End Function
    

    当然,您可以进一步增强检查功能并拥有它们:

    • 更正名称

      例如删除无效字符

    • 承认重复

      例如在它的 and 处添加一个重复名称计数器

    最后,这是一个非常大胆的子代码,它(希望)有意识地利用错误处理删除来避免检查并得到最终结果

    Sub BoldlyAddSheets()
        Dim myCell As Range
        Dim Cities As Range
        Dim mysht As Worksheet
        Dim currentShtName As String
    
        With Sheets("AllCities")
            Set Cities = .Range("A2", .Cells(.Rows.Count, "A").End(xlUp)).SpecialCells(xlCellTypeConstants) '<~~ consider non blank cells of column "A" from cell "A2" down to last non blank cell
        End With
    
        Application.DisplayAlerts = False '<~~ necessary not to have macro interrupted by any prompts risen by possible Delete() method over sheet objects
        On Error Resume Next '<~~ ignore errors -> you must know what you are doing till the next "On Error GoTo 0" statement!
    
        For Each myCell In Cities
            Set mysht = Sheets(myCell.Value) '<~~ try setting a sheet object with the current cell value and ...
            If mysht Is Nothing Then '<~~ ...if unsuccessful then there's no sheet with the wanted name already, so let's try adding it
                Sheets.Add After:=Sheets(Sheets.Count) '<~~ 1) add a new sheet
                currentShtName = ActiveSheet.Name '<~~ 2) store new sheet default name, to check for things to possibly go wrong...
                ActiveSheet.Name = myCell.Value '<~~ 3) try setting the new name...
                If ActiveSheet.Name = currentShtName Then ActiveSheet.Delete '<~~ ...if unsuccessful (sheet name with forbidden characters) delete the sheet
            Else
                Set mysht = Nothing '<~~ set it back to Nothing for subsequent loops
            End If
        Next myCell
    
        Application.DisplayAlerts = True '<~~ at long last ... turn default alerts handling on...
        On Error GoTo 0 '<~~ ... and turn default error handling on, too. this latter just for clarity since "On Error GoTo 0" is automatically done at exiting any sub or function
    End Sub
    

    【讨论】:

      【解决方案4】:

      基于两个假设的附加变体,第一个是包含城市的单元格范围可能包含重复项,第二个是对于某个范围中列出的某些城市,工作表已经添加。

      Sub addsheets()
      
          Dim myCell As Range, Cities As Range, Dic As Object, sh As Worksheet, k
          Set Dic = CreateObject("Scripting.Dictionary"): Dic.CompareMode = vbTextCompare
      
          With Sheets("AllCities")
              Set Cities = .Range("A2:A" & .Cells(Rows.Count, "A").End(xlUp).Row)
          End With
      
          For Each myCell In Cities
          'if value is non blank and not duplicated in a range of cells then add to dictionary
              If myCell.Value2 <> "" And Not Dic.exists(myCell.Value2) Then
                  Dic.Add CStr(myCell.Value2), Nothing
              End If
          Next myCell
      
          For Each sh In ThisWorkbook.Sheets 
          'if sheet with name listed in Cities already exists then remove name from dictionary
              If Dic.exists(sh.Name) Then Dic.Remove (sh.Name)
          Next sh
      
          For Each k In Dic
          'add sheets with unique values stored in dictionary
              Sheets.Add(After:=Sheets(Sheets.Count)).Name = k
          Next k
      
      End Sub
      

      【讨论】:

      • 很好地考虑使用 Dics。至于工作表名称检查逻辑,它会强制您遍历 Sheets 集合的所有工作表以检查每个工作表,而您可以使用特定工作表名称检查一次是否有任何异常。最后还有_invalid sheet name_handling问题
      • @user3598756 感谢您的评论,但我一直在尝试(尽可能)不使用错误处理机制。
      • 我也是!但我也了解到,在极少数特定情况下,使用它几乎是错误的,例如检查任何集合中的项目。
      • @user3598756 我不会和你争论,我想,有多少人,有多少风格和观点,取决于习惯、经验等。我认为,将自己的观点强加给他人并不是真的必要,有时只要表明正确的方向就足够了。
      • 可悲的是,有些人的风格和观点是提出问题,让其他人像我、你和@GaryEvans 投入时间并给出(好的)答案,但在全部!从今以后我会追上这种人的……
      猜你喜欢
      • 2017-12-21
      • 1970-01-01
      • 1970-01-01
      • 2017-07-20
      • 1970-01-01
      • 2011-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多