【发布时间】:2016-06-13 04:40:03
【问题描述】:
我今天刚刚在我的部门发布了一个 Excel 插件,我在过去 2 个月内一直在努力检查大约 30 个验证错误。我在所有情况下都处理了错误捕获(就像现在出现的那样),但是今天我收到了一个可怕的叫醒电话,因为我收到了两个重要错误的自动电子邮件(我在错误处理中内置的一个功能)。第一个在下面,第二个我会单独贴出来。
第一个错误与.Find what:= 字符限制有关
抛出此错误的Sub如下
'Converts Upcharge columns to all uppercase as a safety protocol,
'Checks for colons in option names and removes them from the Option Name column and in the
'upcharge columns if any upcharges correspond to that option name for the particular product.
Private Sub colOpNaCheck()
On Error GoTo ErrHandler
Application.StatusBar = "(11/16) Checking option names for colons"
Dim rng As Range, aCell As Range, uRng1 As Range, uRng2 As Range, uCell As Range, tempC As Range
Dim endRange As Long
Dim opName As String, opName2 As String
Dim xid As String
endRange = ActiveSheet.Range("A" & Rows.count).End(xlUp).Row
Set rng = ActiveSheet.Range("W1:W" & endRange)
Set aCell = rng.Find(What:=":", LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'Add colon to beginning and end of string to ensure we only find and replace the right
'portion over in upcharge column
opName = ":" & aCell.Value & ":"
'Correct the value in column W
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to beginning and
'end of string
opName2 = ":" & aCell.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & aCell.Row).Value
'We have the option name and the xid associated with it
'Now we have to do a find in the upcharges column to see if we find the opName
'Then we do an if statement and only execute if the the Column A XID value matches
'the current xid value we have now
Set uRng1 = ActiveSheet.Range("CT1:CT" & endRange)
Set uRng2 = ActiveSheet.Range("CU1:CU" & endRange)
'Convert uRng1 & uRng2 to all uppercase just to make sure they will be detected when using Find
ActiveSheet.Range(uRng1, uRng2).Select
For Each tempC In Selection
'If cell does not contain an Error AND is not missing a value/is empty AND cell is not already all uppercase
'AND Row is not 1. All of these checks help us save on processing time
If Not IsError(tempC) And Not IsMissing(tempC) And tempC.Value <> UCase(tempC.Value) And tempC.Row <> 1 Then
tempC.Value = UCase(tempC)
End If
Next tempC
'Set uCell to the first instance of opName
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'If there is an instance of opName and uCell has the value check if the xid matches
'to ensure we 're changing the right upcharge
Do
'Check the upcharges
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
Do While ActiveSheet.Range("A" & uCell.Row).Value = xid
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'Correct the value in column CT
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
uCell = Replace(UCase(ActiveSheet.Range("CT" & uCell.Row).Value), UCase(opName), UCase(opName2))
Else
Exit Do
End If
Else
Exit Do
End If
Loop
End If
'Now we look in upcharge_criteria_2 column
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
Do While ActiveSheet.Range("A" & uCell.Row).Value = xid
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'Correct the value in column CU
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
uCell = Replace(UCase(ActiveSheet.Range("CU" & uCell.Row).Value), UCase(opName), UCase(opName2))
Else
Exit Do
End If
Else
Exit Do
End If
Loop
End If
'Exit the Do Statement since we've fixed all the upcharges for this particular Option Name
Exit Do
Loop
Do
'Check for Options
Set aCell = rng.Find(What:=":", LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'Add colon to beginning and end of string to ensure we only find and
'replace the right portion over in upcharge column
opName = ":" & aCell.Value & ":"
'Correct the value in column W (Option_Name)
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to
'beginning and end of string
opName2 = ":" & aCell.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & aCell.Row).Value
Do
'Check the upcharges
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
Do While ActiveSheet.Range("A" & uCell.Row).Value = xid
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'Correct the value in column CT
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
uCell = Replace(UCase(ActiveSheet.Range("CT" & uCell.Row).Value), UCase(opName), UCase(opName2))
Else
Exit Do
End If
Else
Exit Do
End If
Loop
End If
'Now we look in upcharge_criteria_2 column
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
Do While ActiveSheet.Range("A" & uCell.Row).Value = xid
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'Correct the value in column CU
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
uCell = Replace(UCase(ActiveSheet.Range("CU" & uCell.Row).Value), UCase(opName), UCase(opName2))
Else
Exit Do
End If
Else
Exit Do
End If
Loop
End If
'Exit the Do Statement since we've fixed all the upcharges for this particular Option Name
Exit Do
Loop
Else
Exit Do
End If
Loop
End If
Exit Sub
ErrHandler: 'This raises the error back to the parent Sub where my Email on error handler records the error
Err.Raise Err.Number, "colOpNaCheck", Err.Description
End Sub
这一行出现Error 13: Type Mismatch错误
'Set uCell to the first instance of opName
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
发生此错误时opName的值为
"Order Changes. Any changes made to orders after receipt of initial PO must be made in writing via e-mail or fax. Each change will be billed. All changes made the same day as order shipment will be billed. All changes made the same day as order shipment must be received before 3:00 pm EST."
它应该查找/替换的值位于这两个字符串的中间
1. "PROP:ORDER CHANGES. ANY CHANGES MADE TO ORDERS AFTER RECEIPT OF INITIAL PO MUST BE MADE IN WRITING VIA E-MAIL OR FAX. EACH CHANGE WILL BE BILLED. ALL CHANGES MADE THE SAME DAY AS ORDER SHIPMENT WILL BE BILLED. ALL CHANGES MADE THE SAME DAY AS ORDER SHIPMENT MUST BE RECEIVED BEFORE 3:00 PM EST.:EACH CHANGE"
2. "PROP:ORDER CHANGES. ANY CHANGES MADE TO ORDERS AFTER RECEIPT OF INITIAL PO MUST BE MADE IN WRITING VIA E-MAIL OR FAX. EACH CHANGE WILL BE BILLED. ALL CHANGES MADE THE SAME DAY AS ORDER SHIPMENT WILL BE BILLED. ALL CHANGES MADE THE SAME DAY AS ORDER SHIPMENT MUST BE RECEIVED BEFORE 3:00 PM EST.:ALL CHANGES MADE THE SAME DAY AS ORDER SHIPMENT"
我的问题:
- 如何解决这个
.Find what:=限制,同时尽可能少地对我的代码进行调整? - 您能帮我看看如何实施解决方法吗?
更新:快到了
感谢 Tim 的建议和方法,我现在有了以下代码
'Converts Upcharge columns to all uppercase as a safety protocol,
'Checks for colons in option names and removes them from the Option Name column and in the
'upcharge columns if any upcharges correspond to that option name for the particular product.
Private Sub colOpNaCheck()
'Application.StatusBar = "(11/16) Checking option names for colons"
Dim onRng As Range, uRng1 As Range, uRng2 As Range, tempC As Range
Dim aCell As Collection, uCell As Collection, el, el2, el3
Dim endRange As Long
Dim opName As String, opName2 As String, xid As String
endRange = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Set onRng = ActiveSheet.Range("W1:W" & endRange)
Set uRng1 = ActiveSheet.Range("CT1:CT" & endRange)
Set uRng2 = ActiveSheet.Range("CU1:CU" & endRange)
Set aCell = FindAllMatches(onRng, ":")
If Not aCell Is Nothing Then
'Convert uRng1 & uRng2 to all uppercase
' ActiveSheet.Range(uRng1, uRng2).Select
' For Each tempC In Selection
' 'If cell does not contain an Error AND is not missing a value/is empty AND cell is not already all uppercase
' 'AND Row is not 1. All of these checks help us save on processing time
' If Not IsError(tempC) And Not IsMissing(tempC) And tempC.Value <> UCase(tempC.Value) And tempC.Row <> 1 Then
' tempC.Value = UCase(tempC)
' End If
' Next tempC
For Each el In aCell
'Add colon to beginning and end of string to ensure we only find and replace the right
'portion over in upcharge column
opName = ":" & el.Value & ":"
'Correct the value in column W
el.Value = Replace(ActiveSheet.Range("W" & el.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to beginning and
'end of string
opName2 = ":" & el.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & el.Row).Value
'We have the option name and the xid associated with it
'Now we have to do a find in the upcharges column to see if we find the opName
'Then we do an if statement and only execute if the Column A XID value matches
'the current xid value we have now
'set all instances of opName to uCell
Set uCell = FindAllMatches(uRng1, opName)
If Not uCell Is Nothing Then
For Each el2 In uCell
'Correct the value in column CT
el2.Value = Replace(UCase(ActiveSheet.Range("CT" & el2.Row).Value), UCase(opName), UCase(opName2))
Next el2
End If
Set uCell = FindAllMatches(uRng2, opName)
If Not uCell Is Nothing Then
For Each el3 In uCell
'Correct the value in column CT
el3.Value = Replace(UCase(ActiveSheet.Range("CT" & el3.Row).Value), UCase(opName), UCase(opName2))
Next el3
End If
Next el
End If
End Sub
Function FindAllMatches(rng As Range, txt As String) As Collection
Dim rv As New Collection, f As Range, addr As String, txtSrch As String
Dim IsLong As Boolean
IsLong = Len(txt) > 250
txtSrch = IIf(IsLong, Left(txt, 250), txt)
Set f = rng.Find(what:=txtSrch, lookat:=xlPart, MatchCase:=False)
Do While Not f Is Nothing
If f.Address(False, False) = addr Then Exit Do
If Len(addr) = 0 Then addr = f.Address(False, False)
'check for the *full* value
If InStr(f.Value, txt) > 0 Then rv.Add f
Set f = rng.FindNext(after:=f)
Loop
Set FindAllMatches = rv
End Function
但是,当我使用他的函数通过这些行在 upcharge 列中查找所有实例时
'set all instances of opName to uCell
Set uCell = FindAllMatches(uRng1, opName)
If Not uCell Is Nothing Then
...
uCell 总是在 Watch 窗口中显示 No Variables,即使是我上面提到的值。我究竟做错了什么?还是FindAllMatches功能需要调整?
【问题讨论】:
-
我来自我的牢房,无法检查代码,但我看到您使用 String car 来存储 FIND 中的内容。使用 MSGBOX 找到从 FIND 中找到的地址。这样:MSGBOX uRng1.Find(What: =Ucase(opName)).address 并检查值
-
.find 有 255 个字符的限制。您可以在与不区分大小写进行比较时消除
UCASE命令。 -
@ElbertVillarreal,这就是问题所在。
opName字符太多,所以uRng1.Find什么都不返回。 -
@nbayly 谢谢,如上所述,我已经知道字符数限制,这正是我发布这个问题的原因。今天早些时候我也意识到我的
UCase是不必要的,但在发布之前忘记删除它。 -
不用担心 CaffeinatedCoder,我的评论更多是为了 Elbert 的利益。尽管不包含编码,但我正在提出有关如何解决此问题的建议作为答案。更像是一个概念。
标签: vba excel replace type-mismatch