如何将包含多个值(逗号分隔)的单元格拆分为单独的行?

时间:2016-09-27 13:23:15

标签: excel vba excel-vba split

我正在处理一些数据样本,我希望根据逗号分隔符将其拆分为多行。拆分前Excel中的数据表如下所示:

This is what the table looks like before the desired transformation

我希望开发VBA代码以在C列('公司联系点')中拆分值,并为每个公司联系点创建单独的行。

到目前为止,我已设法将C列中的值拆分为单独的行。但是我还没有设法在列D(关系长度)和E(关系强度)中拆分值,因此用逗号分隔的每个值对应于列C中它们各自的联系。

Finally I'd like my table to look like this

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

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

go-github

2 个答案:

答案 0 :(得分:2)

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

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

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

以下是您可以使用的代码:

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

答案 1 :(得分:2)

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

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

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

我定义为

的两个类
  • 网站(我假设每个网站只有一个网站联系人,但如果需要,可以轻松更改),并提供以下信息:

    • 网站名称
    • 网站密钥联系
    • 和公司联系信息词典
  • 公司联系方式,其中包含

    的信息
    • 名称
    • 关系长度
    • 关系的力量

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

正如您所看到的,如果需要,可以非常简单地向Class中添加其他信息。

输入两个类模块和一个常规模块 重命名类模块,如注释

中所示

请务必设置对 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