使用excel vba

时间:2016-04-02 22:39:56

标签: arrays regex excel vba excel-vba

我有一个非常多余的旧代码,我在第一次发现并决定学习vba时创建了这个代码(而且我有很长的路要走)。我正在使用此代码循环遍历包含用逗号分隔的多个值的单元格。但是,有些情况下我不能简单地使用诸如Split(string,",")函数之类的东西,因为某些值在该值中有逗号(示例值: [blah blah,so blah blah] )。在存在这些括号的情况下(它们围绕着其中包含逗号的每个值)我设计了相当啰嗦的方法,这是我的旧方法,正确地将值拆分,将它们转储到数组中,然后继续我的其他任务。但是,现在我决定重新审视代码并修复准确性。这是一些背景知识。

可以在一个单元格中找到的示例数据:
请注意:这是供应商发送给我们的数据,我们无法控制他们输入的内容或输入方式。这是一个简单的例子,展示了在某些情况下通常如何提供数据的要点

Available on 2 sides: Silkscreen,[full: color, covers entire face],Pad Print: One color,[heat transfer, may bleed]

值为:

  • 有两面可供选择:丝网印刷
  • [完整:颜色,覆盖整个脸部]
  • 打印垫:一种颜色
  • [传热,可能会流血]

我在寻找什么:
我正在寻找一种更有效,更简单的方法,能够正确地分割值(同时保留包含它们的值的括号)。

我相信我已设法使用以下代码创建一个更高效,更紧凑的方法来处理不包含括号的实例

新规范(在建): 我有问题,不知道如何有效和准确地用括号分割单元格

Sub Test()
    Dim rngXid As Range, RegularColons As New Collection, UpchargeColons As New Collection, additionals As Range, upcharges As Range, Colon, UpchargeColon
    Dim Values() As String, endRange As Long, xidMap As Object, xid As String, NumberofValues As Integer
    endRange = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row

    Set xidMap = getXidMap(ActiveSheet.Range("A2:A" & UsedRange.Rows.Count)) 'Map products for quicker navigation
    Set additionals = ActiveSheet.Range("AJ:AK"): Set upcharges = ActiveSheet.Range("CS:CT")
    Set RegularColons = FindAllMatches(additionals, ":") 'This returns all instances/cells that contain a colon in the specified columns
    If Not RegularColons Is Nothing Then
        For Each Colon In RegularColons
            xid = ActiveSheet.Range("A" & Colon.Row).Value
            If InStr(1, Colon.Value, "[") = 0 Then 'If no brackets then simply split
                Values = Split(Trim(Colon.Value), ",")
            Else
                'This is where I'm at a lose for a more effective method
                '-----------Populate Values array with Colon.Value while watching out for brackets--------
            End If
            Set rngXid = xidMap(xid).EntireRow.Columns(upcharges) 'set to this specific product
            For ColorLocation = LBound(Values) To UBound(Values) 'cycle through each value in Values array
                If Not InStr(1, Values(ColorLocation), ":") = 0 Then 'Only proceed if the value has a colon
                    Set UpchargeColons = FindAllMatches(rngXid, Values(ColorLocation)) 'Searching other columns for this value
                    If Not UpchargeColons Is Nothing Then
                        For Each UpchargeColon In UpchargeColons 'If found in other columns proceed to replace colon
                            UpchargeColon.Value = Replace(UpchargeColon.Value, ":", " ")
                            Log UpchargeColon.Range, "Removed Colon from Additional Color/Location Upcharge", "Corrected" 'This is a custom sub of mine to record the change
                        Next UpchargeColon
                    End If
                    Values(ColorLocation) = Replace(Values(ColorLocation), ":", " ")
                End If
            Next ColorLocation
            Log Colon.Range, "Removed Colon(s) from Additional Color/Location Value(s)", "Corrected"
        Next Colon
    End If
End Sub

我一直在寻找可能的方法来做到这一点而且一直坚持的是Regex,我承认我完全没有经验,尽管我之前已经听说过。所以,我尝试使用像this这样的网站,当然还有msdn documentation来阅读它。我在尝试更多地了解这种方法时的观察/想法是:

  1. 这绝对是非常复杂和压倒性的。因此,我必须避免爬进角落,假设胎位,并睁大眼睛。
  2. 我似乎无法找到任何可以建议我如何将此功能合并到我需要适当拆分字符串的任何内容,至少就我所见。但是,可能只是因为我被所有看似随机的符号序列所淹没
  3. 所以,我的问题是:
    在包含括号的单元格中准确分割值的最有效方法是什么?

4 个答案:

答案 0 :(得分:3)

还有其他方法,但这个正则表达式看起来非常快:

(\[[^\]]+\]|[^,]+),?

说明:

\[\][]的转义版本

基本上,它正在寻找\[,获取所有非括号[^\]],然后是\]。否则|,它将获得所有非逗号[^,]。周围的()使其成为捕获组。 ,?表示可能有也可能没有逗号。

答案 1 :(得分:3)

一种方法是使用括号中的逗号并将其替换为 Chr(184)。这些小家伙看起来很像逗号。

更换括号内的逗号后,您可以使用普通的 Split()以下是一些代码来进行替换:

Sub parser()
    Dim s As String, s1 As String, s2 As String, pseudo As String
    Dim switch As Boolean, temp As String, CH As String

    pseudo = Chr(184)
    s1 = "["
    s2 = "]"
    s = [A1]
    switch = False
    temp = ""

    For i = 1 To Len(s)
        CH = Mid(s, i, 1)
        If CH = s1 Or CH = s2 Then switch = Not switch
        If switch Then CH = Replace(CH, ",", pseudo)
        temp = temp & CH
    Next i

    Range("A2").Value = temp
    MsgBox s & vbCrLf & temp
End Sub

enter image description here

答案 2 :(得分:2)

正则表达式(又名“正则表达式”)确实很吓人,但它们也是一个强大的工具,如果你添加对 Microsoft VBScript正则表达式5.5 的引用,VBA支持它们库。

有了它,你可以创建一个RegExp对象,它会给你一个MatchCollection,它是一个Match个对象的集合。

以下是如何使用它们:

Sub Test()
    Const value As String = _
    "Available on 2 sides: Silkscreen,[full: color, covers entire face],Pad Print: One color,[heat transfer, may bleed]"

    Const pattern As String = _
    "(\[[^\]]+\]|[^,]+)"

    Dim regex As New RegExp
    regex.Global = True
    regex.pattern = pattern

    Dim matches As MatchCollection
    Set matches = regex.Execute(value)

    Dim m As Match
    For Each m In matches
        Debug.Print Trim(m.value) 'value will preserve any leading/trailing spaces
    Next

End Sub

请注意,pattern中的(\[[^\]]+\]|[^,]+) 几乎与Laurel's answer相同:

Available on 2 sides: Silkscreen
[full: color, covers entire face]
Pad Print: One color
[heat transfer, may bleed]

通过不指定您想要匹配逗号,您不匹配它(无论它是否存在) - 因此,上面的代码输出:

MatchCollection

如果需要,可以轻松迭代{{1}}以填充数组。

答案 3 :(得分:1)

Document