工作的VBA脚本,突然抛出错误?

时间:2013-11-03 23:39:23

标签: regex excel vba excel-vba

以下代码我在Excel工作表上。我正在使用VBA来改变某些单元格的内容,以便为我的工作正确格式化它们。我们会列出损坏,海湾位置和VIN。这些列中的每一列都有自己的特定格式,其中2个我工作正常。你们中的一些人可能会从另一篇关于正确格式化损坏代码的帖子中认出这些代码。列按此顺序排列

Bay Location | VIN | Damage Code(s)

对于VIN,我们所做的只是大写字母。很简单,完成了。在我改变它以更好地满足我的需要之后,损坏代码功能完美地工作。没有我在这里收到的原始帮助,就不可能做到这一点。在这里,事情变得奇怪,我的老板,看到我已经让这个为损坏代码工作,让我把它变成自动格式化托架。我工作的海湾位置有一些可能性,但前面至少有一个字母,如

  1. H-5
  2. H-125
  3. HH-50
  4. 7A-70
  5. FNCE-13
  6. 在英语中,我想要做的是:  输入未格式化的托架,例如7a12,大写字母,用数字分割,并在两组之间添加一个破折号,然后瞧。

    我有这个工作,甚至向我的老板展示。但后来我在代码中添加了大写VIN列,我开始收到错误,突出显示行

    Set allMatches = RE1.Execute(strSource)
    

    RE1.test(strSource)运行正常,但现在尝试抓取匹配/子匹配会神秘地抛出错误。我最初使用This StackOverflow question中的文字来使其正常工作。我得到的错误类似于它告诉我没有设置对象。我知道代码目前是乱七八糟的,我不得不离开中间工作(想想我的函数可能出现问题,nope,直接从原始子函数运行时出现同样的错误)。

    编辑:错误如下

      

    运行时错误'91'   对象变量或未设置块变量

    再次强调

    allMatches = RE.Execute(str)
    

    感谢任何帮助。

    Private Sub Worksheet_Change(ByVal Target As Range)
        Dim KeyCells As Range
        Dim str As String, result As String
        Dim RE As Object
        Dim allMatches As Object
    
        ' The variable KeyCells contains the cells that will
        ' cause an alert when they are changed.
        Set KeyCells = Application.Union(Range("F3:F100"), Range("C3:C100"), Range("I3:I100"))
        Set RE = CreateObject("vbscript.regexp")
    
        If Not TypeName(Target.Value) = "Variant()" Then
    
            If Not Application.Intersect(KeyCells, Range(Target.Address)) _
                Is Nothing Then
    
                ' Display a message when one of the designated cells has been
                ' changed.
                ' Place your code here.
                str = ConvertString(Target)
                If (Not str = Target.Value And Not Target.Value = "") Then
                    Target.Value = str
                End If
    
            End If
    
            ' Now we have to check the bays in order to auto format
            Set KeyCells = Application.Union(Range("A3:A100"), Range("D3:D100"), Range("G3:G100"))
            If Not Application.Intersect(KeyCells, Range(Target.Address)) _
                Is Nothing Then
    
                RE.Pattern = "([0-9]?[A-Z]{1,})\-?([0-9]{1,3})"
                RE.Global = True
    
                If Not Target.Value = "" And Not RE.test(Target.Value) Then
                        str = CStr(Target.Value)
                        RE.IgnoreCase = True
                        allMatches = RE.Execute(str)
                        MsgBox allMatches.Count
    
                        Target.Value = str
                End If
    
            End If
    
            Set KeyCells = Application.Union(Range("B3:B100"), Range("E3:E100"), Range("H3:H100"))
    
            If Not Application.Intersect(KeyCells, Range(Target.Address)) _
                Is Nothing Then
    
                RE.Pattern = "[a-z]?"
                RE.IgnoreCase = False
    
                If RE.test(Target.Value) Then
                    Target.Value = UCase(Target.Value)
                End If
    
            End If
        End If
    End Sub
    Function FormatBay(str1 As Range) As String
        Dim result As String, strSource As String
        Dim allMatches As Object
        Dim RE1 As Object
        Set RE1 = CreateObject("vbscript.regexp")
        RE1.Pattern = "([0-9]?[A-Z]{1,})\-?([0-9]{1,3})"
        RE1.Global = True
        strSource = CStr(str1.Value)
        Set allMatches = RE1.Execute(strSource)
        result = "FF-12"
        If allMatches.Count <> 0 Then
            result = allMatches.Item(0)
        End If
        MsgBox result
        FormatBay = result
    End Function
    Function ConvertString(str1 As Range) As String
        Dim varStr As Variant
        Dim strSource As String, strResult As String
        Dim i As Integer
    
        For Each varStr In Split(Trim(str1.Value), " ")
    
                strSource = CStr(varStr)
            If InStr(strSource, ".") = 0 Then
                strResult = strResult & _
                    Mid(strSource, 1, 2) & "." & _
                    Mid(strSource, 3, 2) & "." & _
                    Mid(strSource, 5, 1)
                If Len(strSource) > 5 Then
                    strResult = strResult & "("
                    For i = 6 To Len(strSource)
                        strResult = strResult & Mid(strSource, i, 1) & ","
                    Next i
                    strResult = Left(strResult, Len(strResult) - 1) & ")"
                End If
                strResult = strResult & " "
            Else
                strResult = strResult & strSource & " "
            End If
        Next
    
        If strResult = "" Then
            ConvertString = ""
        Else
            ConvertString = Left(strResult, Len(strResult) - 1)
        End If
    End Function
    

    编辑 :这就是我的工作,我知道它有点长,可能很冗长,但我只是在学习VBA,所以当我学到更好的东西时为了做到这一点,我将编辑这篇文章,希望以后可以帮助别人。

    Private Sub Worksheet_Change(ByVal Target As Range)
        Dim KeyCells As Range
        Dim str As String, result As String
        Dim RE As Object
        Dim allMatches As Object
    
        ' The variable KeyCells contains the cells that will
        ' cause an alert when they are changed.
        Set KeyCells = Application.Union(Range("F3:F100"), Range("C3:C100"), Range("I3:I100"))
        Set RE = CreateObject("vbscript.regexp")
    
        If Not TypeName(Target.Value) = "Variant()" Then
    
    
            ' Now we have to check the bays in order to auto format
            Set KeyCells = Application.Union(Range("A3:A100"), Range("D3:D100"), Range("G3:G100"))
            If Not Application.Intersect(KeyCells, Range(Target.Address)) _
                Is Nothing Then
    
                RE.Pattern = "([0-9]?[A-Z]{1,})\-?([0-9]{1,3})"
                RE.Global = True
    
                If Not Target.Value = "" And Not RE.test(Target.Value) Then
                        str = CStr(Target.Value)
                        str = FormatBay(str)
    
                        Target.Value = str
                End If
    
            End If
    
            Set KeyCells = Application.Union(Range("B3:B100"), Range("E3:E100"), Range("H3:H100"))
    
            If Not Application.Intersect(KeyCells, Range(Target.Address)) _
                Is Nothing Then
    
                RE.Pattern = "[a-z]?"
                RE.IgnoreCase = False
    
                If RE.test(Target.Value) Then
                    Target.Value = UCase(Target.Value)
                End If
    
            End If
    
            Set KeyCells = Application.Union(Range("C3:C100"), Range("F3:F100"), Range("I3:I100"))
    
            If Not Application.Intersect(KeyCells, Range(Target.Address)) _
                Is Nothing Then
    
                ' Display a message when one of the designated cells has been
                ' changed.
                ' Place your code here.
                str = ConvertString(Target)
                If (Not str = Target.Value And Not Target.Value = "") Then
                    Target.Value = str
                End If
    
            End If
    
        End If
    End Sub
    Function FormatBay(ByVal text As String) As String
    
        Dim result As String, bayLetter As String, bayNumber As String
        Dim length As Integer, i As Integer
        Dim allMatches As Object
        Dim RE As Object
        Set RE = CreateObject("vbscript.regexp")
    
        RE.Pattern = "([0-9]?[a-z]{1,})\-?([0-9]{1,3})"
        RE.Global = True
        RE.IgnoreCase = True
    
        Set allMatches = RE.Execute(text)
    
        If Not allMatches.Count = 0 Then
            bayLocation = allMatches.Item(0).submatches.Item(0)
            bayLocation = UCase(bayLocation)
            bayNumber = allMatches.Item(0).submatches.Item(1)
            length = Len(bayNumber)
    
            For i = 1 To (3 - length)
                bayNumber = "0" & bayNumber
            Next
            result = bayLocation & "-" & bayNumber
        End If
    
        FormatBay = result
    
    End Function
    Function ConvertString(str1 As Range) As String
        Dim varStr As Variant
        Dim strSource As String, strResult As String
        Dim i As Integer
    
        For Each varStr In Split(Trim(str1.Value), " ")
    
                strSource = CStr(varStr)
            If InStr(strSource, ".") = 0 And IsNumeric(strSource) Then
                strResult = strResult & _
                    Mid(strSource, 1, 2) & "." & _
                    Mid(strSource, 3, 2) & "." & _
                    Mid(strSource, 5, 1)
                If Len(strSource) > 5 Then
                    strResult = strResult & "("
                    For i = 6 To Len(strSource)
                        strResult = strResult & Mid(strSource, i, 1) & ","
                    Next i
                    strResult = Left(strResult, Len(strResult) - 1) & ")"
                End If
                strResult = strResult & " "
            Else
                strResult = strResult & strSource & " "
            End If
        Next
    
        If strResult = "" Then
            ConvertString = ""
        Else
            ConvertString = Left(strResult, Len(strResult) - 1)
        End If
    End Function
    

2 个答案:

答案 0 :(得分:1)

allMatches是一个对象(Type = MatchCollection)变量。在分配对象变量时,应使用Set关键字。

Set allMatches = RE.Execute(str)

正如您的代码目前所代表的那样,除非您或其他人对代码进行了无意的编辑并更改了此变量的分配方式,否则我认为它不会在没有引发此错误的情况下工作。

希望这有帮助!

答案 1 :(得分:0)

首先,正则表达式[a-z]?始终匹配。如果Target.Value中的第一个字符恰好是小写字母,则正则表达式将使用它。否则它将匹配之前的空字符串第一个字符。您正在测试是否存在小写字母,但是?通过使该字母可选来使目的失败。

但我不明白为什么你需要做那个测试。无论如何你要将所有字母都改成大写,对吧?所以只需要UCase字符串并完成它。或者等到转换完成后再UCase

至于实际的转换,你的代码相当混乱,但我认为你做了很多不必要的工作。如果你单独处理7a12之类的字符串,这应该就足够了:

RE.Pattern = "^([0-9]?[A-Z]{1,})-?([0-9]{1,3})$"
RE.IgnoreCase = True
result = UCase(RE.Replace(source, "$1-$2"))

或者我错过了什么?