【问题标题】:How to split cells containing multiple values (comma delimited) into separate rows?如何将包含多个值(逗号分隔)的单元格拆分为单独的行?
【发布时间】:2017-02-05 03:42:16
【问题描述】:

我正在处理一个数据样本,我想根据逗号分隔符将其分成几行。拆分前我在 Excel 中的数据表如下所示:

我想开发 VBA 代码来拆分 C 列(“公司联系点”)中的值,并为每个“公司联系点”创建单独的行。

到目前为止,我已经设法将 C 列中的值拆分为单独的行。但是,我还没有设法拆分 D 列(关系长度)和 E(关系强度)中的值,以便用逗号分隔的每个值对应于 C 列中的相应联系人。

您将在下面找到我用来拆分单元格的代码示例。这段代码的限制是它没有拆分我表中的其他列,只拆分了一个。

如何使此代码能够拆分其他列中的值?

Sub Splt()
    Dim LR As Long, i As Long
    Dim X As Variant
    Application.ScreenUpdating = False
    LR = Range("A" & Rows.Count).End(xlUp).Row
    Columns("A").Insert
    For i = LR To 1 Step -1
        With Range("B" & i)
            If InStr(.Value, ",") = 0 Then
                .Offset(, -1).Value = .Value
            Else
                X = Split(.Value, ",")
                .Offset(1).Resize(UBound(X)).EntireRow.Insert
                .Offset(, -1).Resize(UBound(X) - LBound(X) + 1).Value = Application.Transpose(X)
            End If
        End With
    Next i
    Columns("B").Delete
    LR = Range("A" & Rows.Count).End(xlUp).Row
    With Range("B1:C" & LR)
        On Error Resume Next
            .SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
         On Error GoTo 0
         .Value = .Value
    End With

    Application.ScreenUpdating = True
End Sub

【问题讨论】:

    标签: vba excel split


    【解决方案1】:

    您不仅应该迭代行,还应该迭代列,并检查每个单元格中是否有这样的逗号。当一行中至少有一个单元格有逗号时,应将其拆分。

    然后您可以插入该行,并将逗号之前的部分复制到新创建的行中,同时从原始行中删除该部分,然后将其向上移动一个索引。

    您还应该注意在插入行时增加要遍历的行数,否则您将完成一项不完整的工作。

    这是您可以使用的代码:

    Sub Splt()
        Dim LR As Long, LC As Long, r As Long, c As Long, pos As Long
        Dim v As Variant
    
        Application.ScreenUpdating = False
        LR = Cells(Rows.Count, 1).End(xlUp).Row
        LC = Cells(1, Columns.Count).End(xlToLeft).Column
        r = 2
        Do While r <= LR
            For c = 1 To LC
                v = Cells(r, c).Value
                If InStr(v, ",") Then Exit For ' we need to split
            Next
            If c <= LC Then ' We need to split
                Rows(r).EntireRow.Insert
                LR = LR + 1
                For c = 1 To LC
                    v = Cells(r + 1, c).Value
                    pos = InStr(v, ",")
                    If pos Then
                        Cells(r, c).Value = Left(v, pos - 1)
                        Cells(r + 1, c).Value = Trim(Mid(v, pos + 1))
                    Else
                        Cells(r, c).Value = v
                    End If
                Next
            End If
            r = r + 1
        Loop
        Application.ScreenUpdating = True
    End Sub
    

    【讨论】:

    • 谢谢,你的回答很有用!
    【解决方案2】:

    我会采用一种方法,使用用户定义的对象(类)和字典来收集和重组数据。使用易于理解的名称,以便日后维护和调试。

    此外,通过使用 VBA 数组,宏的执行速度应该比对工作表的多次读取和写入要快得多

    然后将数据重新编译成所需的格式。

    我定义的两个类

    • 站点(我假设每个站点只有一个站点联系人,尽管如果需要,很容易更改),并提供以下信息:

      • 网站名称
      • 网站主要联系人
      • 和公司联系信息字典
    • 公司联系人,其中包含以下信息

      • 姓名
      • 关系长度
      • 关系强度

    我会检查以确保最后三列中的条目数量相同。

    如您所见,如果需要,向任一类添加额外信息将相当简单。

    输入两个类模块和一个常规模块 重命名 Class Modules 如 cmets 所示

    请务必设置对 Microsoft Scripting Runtime 的引用,以便能够使用 Dictionary 对象。

    此外,您可能需要为源/结果工作表/范围重新定义 wsSrcwsResrRes。为方便起见,我将它们放在同一个工作表上,但没有必要。

    类模块 1

    Option Explicit
    'Rename this to: cSite
    'Assuming only a single Site Key Contact per site
    
    Private pSite As String
    Private pSiteKeyContact As String
    Private pCompanyContactInfo As Dictionary
    Private pCC As cCompanyContact
    
    Public Property Get Site() As String
        Site = pSite
    End Property
    Public Property Let Site(Value As String)
        pSite = Value
    End Property
    
    Public Property Get SiteKeyContact() As String
        SiteKeyContact = pSiteKeyContact
    End Property
    Public Property Let SiteKeyContact(Value As String)
        pSiteKeyContact = Value
    End Property
    
    Public Property Get CompanyContactInfo() As Dictionary
        Set CompanyContactInfo = pCompanyContactInfo
    End Property
    
    Public Function AddCompanyContactInfo(ByVal CompanyContact As String, _
        ByVal RelationshipLength As String, ByVal RelationshipStrength As String)
        Set pCC = New cCompanyContact
        With pCC
            .CompanyContact = CompanyContact
            .LengthOfRelationship = RelationshipLength
            .StrengthOfRelationship = RelationshipStrength
            pCompanyContactInfo.Add Key:=.CompanyContact, Item:=pCC
        End With
    End Function
    
    Private Sub Class_Initialize()
        Set pCompanyContactInfo = New Dictionary
    End Sub
    

    类模块 2

    Option Explicit
    'Rename to: cCompanyContact
    Private pCompanyContact As String
    Private pLengthOfRelationship As String
    Private pStrengthOfRelationship As String
    
    Public Property Get CompanyContact() As String
        CompanyContact = pCompanyContact
    End Property
    Public Property Let CompanyContact(Value As String)
        pCompanyContact = Value
    End Property
    
    Public Property Get LengthOfRelationship() As String
        LengthOfRelationship = pLengthOfRelationship
    End Property
    Public Property Let LengthOfRelationship(Value As String)
        pLengthOfRelationship = Value
    End Property
    
    Public Property Get StrengthOfRelationship() As String
        StrengthOfRelationship = pStrengthOfRelationship
    End Property
    Public Property Let StrengthOfRelationship(Value As String)
        pStrengthOfRelationship = Value
    End Property
    

    常规模块

    Option Explicit
    'Set Reference to Microsoft Scripting Runtime
    
    Sub SiteInfo()
        Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
        Dim vSrc As Variant, vRes As Variant
        Dim cS As cSite, dS As Dictionary
        Dim I As Long, J As Long
        Dim V As Variant, W As Variant, X As Variant
    
    'Set source and results worksheets and results range
    Set wsSrc = Worksheets("Sheet4")
    Set wsRes = Worksheets("Sheet4")
        Set rRes = wsRes.Cells(1, 10)
    
    'Get source data
    With wsSrc
        vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 5).End(xlUp))
    End With
    
    'Split and collect the data into objects
    Set dS = New Dictionary
    For I = 2 To UBound(vSrc, 1) 'skip first row
        Set cS = New cSite
            V = Split(vSrc(I, 3), ",")
            W = Split(vSrc(I, 4), ",")
            X = Split(vSrc(I, 5), ",")
    
            If Not UBound(V) = UBound(W) And UBound(V) = UBound(X) Then
                MsgBox "Mismatch in Company Contact / Length / Strength"
                Exit Sub
            End If
    
        With cS
            .Site = vSrc(I, 1)
            .SiteKeyContact = vSrc(I, 2)
            For J = 0 To UBound(V)
    
            If Not dS.Exists(.Site) Then
                .AddCompanyContactInfo Trim(V(J)), Trim(W(J)), Trim(X(J))
                dS.Add .Site, cS
            Else
                dS(.Site).AddCompanyContactInfo Trim(V(J)), Trim(W(J)), Trim(X(J))
            End If
    
            Next J
        End With
    Next I
    
    'Set up Results array
    I = 0
    For Each V In dS
        I = I + dS(V).CompanyContactInfo.Count
    Next V
    
    ReDim vRes(0 To I, 1 To 5)
    
    'Headers
        For J = 1 To UBound(vRes, 2)
            vRes(0, J) = vSrc(1, J)
        Next J
    
    'Populate the data
    I = 0
    For Each V In dS
        For Each W In dS(V).CompanyContactInfo
            I = I + 1
            vRes(I, 1) = dS(V).Site
            vRes(I, 2) = dS(V).SiteKeyContact
            vRes(I, 3) = dS(V).CompanyContactInfo(W).CompanyContact
            vRes(I, 4) = dS(V).CompanyContactInfo(W).LengthOfRelationship
            vRes(I, 5) = dS(V).CompanyContactInfo(W).StrengthOfRelationship
        Next W
    Next V
    
    'Write the results
    Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
    With rRes
        .EntireColumn.Clear
        .Value = vRes
        With .Rows(1)
            .Font.Bold = True
            .HorizontalAlignment = xlCenter
        End With
        .EntireColumn.AutoFit
    End With
    
    End Sub
    

    【讨论】:

    • 非常感谢您的帮助!
    猜你喜欢
    • 2012-01-28
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多