I am trying to join these 3 statements together. I can get two to work but not the third.
Check is looking to see if the 5th character = a,b,c,d.
Check0 is looking to see if characterS 2-9 are all numbers.
Check3 is looking to see if the first 3 characters are numbers.
Desired effect
Before > After
Check 0 e01730101.pdf > S-173-0101
Check3 173d00510.pdf > S-173-D005
Check e173d0061.pdf > S-173-D006
Right now Check0 is not working. When I run the code it seems to skip my Case 13 Check0 statement. Anyway i can write this so the 3 checks are not conflicting each other?
Option Explicit
Sub Convert()
Application.ScreenUpdating = False
Dim rng As Range, aCell As Range
Dim val As String, Check, Check0, Check3
Dim LastRow As Long
LastRow = Range("A" & Rows.Count).End(xlUp).Row
Set rng = Range("A2:A" & LastRow)
For Each aCell In rng.Cells
Select Case Len(aCell)
'Case 12 left out
Case 13
Check = Mid(aCell, 5, Len(aCell) - 12)
If Check = "a" Or Check = "b" Or Check = "c" Or Check = "d" Then 'Existing Standard
val = "S-" & Left(aCell, Len(aCell) - 13) & Mid(aCell, 2, Len(aCell) - 10) & "-" & Mid(aCell, 5, Len(aCell) - 9)
Check0 = IsNumeric(Mid(aCell, 2, Len(aCell) - 5)) '|||PROBLEM|||
ElseIf Check0 = True Then 'Existing Three Line Diagrams
val = "S-" & Left(aCell, Len(aCell) - 10) & "-" & Mid(aCell, 4, Len(aCell) - 9)
End If
Check3 = IsNumeric(Left(aCell, 3))
If Check3 = True Then 'Standard after page 9
val = "S-" & Mid(aCell, 1, Len(aCell) - 10) & "-" & Mid(aCell, 4, Len(aCell) - 9)
End If
Check = ""
Check0 = ""
Check3 = ""
'Case 14 left out
Case Else 'All other pages
val = "_Mod " & Left(aCell, Len(aCell) - 4)
End Select
val = UCase(val)
val = val & " " & aCell.Offset(, 2) & aCell.Offset(, 3)
aCell.Offset(, 1).Value = val
Next
Application.ScreenUpdating = True
End Sub
The issue is that your Check0 variable is not initialised when you check it. It would be best to first do all your three checks and only then perform the If...ElseIf....
Secondly, this expression is using the wrong parts of the input string:
val = "S-" & Left(aCell, Len(aCell) - 10) & "-" & Mid(aCell, 4, Len(aCell) - 9)
I don't really understand why you use Len(aCell) - something, since it is known that the length is 13. Certainly Left(aCell, Len(aCell) - 13) is quite useless, as it will be the empty string.
Here is a correction with some other optimisations (pos is a Long):
Case 13
Check = InStr("abcd", Mid(aCell, 5, 1))
Check0 = IsNumeric(Mid(aCell, 2, 8))
Check3 = IsNumeric(Left(aCell, 3))
pos = IIf(Check3, 1, _
IIf(Check, 2, _
IIf(Check0, 3, 0)))
val = IIf(pos, "S-" & Mid(aCell, pos, 3) & "-" & Mid(aCell, pos+3, 4), "??")
Related
I recently created an IF formula to run inside a macro for only 2 statements but I need to add 3 more to it.
This is for altering a filename. So I use the LEN to determine what type of file it is then run the appropriate formula to trim out what I don't want.
Examples:
173d0221.pdf = S-173-D022 Description.pdf
=CHAR(83)&CHAR(45)&LEFT(B11,LEN(B11)-9)&CHAR(45)&UPPER(MID(B11,4,LEN(B11)-8))&CHAR(32)&D11&E11
173d02210.pdf = S-173-D022 Description.pdf =CHAR(83)&CHAR(45)&LEFT(B12,LEN(B12)-10)&CHAR(45)&UPPER(MID(B12,4,LEN(B12)-9))&CHAR(32)&D12&E12
173d170c141.pdf = SD-170-C14 Description.pdf
=CHAR(83)&CHAR(68)&CHAR(45)&UPPER(MID(B13,5,LEN(B13)-12))&CHAR(45)&UPPER(MID(B13,8,LEN(B13)-12)&CHAR(32)&D13&E13)
REF-173d0221.pdf = REF-173-D022 Description.pdf
=LEFT(B14,LEN(B14)-9)&CHAR(45)&UPPER(MID(B14,8,LEN(B14)-12))&CHAR(32)&D14&E14
REF-173d02210.pdf = REF-173-D022 Description.pdf
=LEFT(B15,LEN(B15)-10)&CHAR(45)&UPPER(MID(B15,8,LEN(B15)-13))&CHAR(32)&D15&E15
I am having trouble linking them together to get it to apply the right formula based on the length of the cell.
Notes: I am using CHAR(83)&CHAR(45) instead of "S-" because VBA wasn't liking the text. I will update the "B12" cell tag with " & aCell & " once everything is working smoothly.
My vba code looks like:
.Range("C2:C" & LastRow).Formula = "=IF(LEN(" & aCell & ")=12,CHAR(83)&CHAR(45)&LEFT(" & aCell & ",LEN(" & aCell & ")-9)&CHAR(45)&UPPER(MID(" & aCell & ",4,LEN(" & aCell & ")-8))&CHAR(32)&" & dCell & "&" & eCell & ",LEFT(" & aCell & ",LEN(" & aCell & ")-9)&CHAR(45)&UPPER(MID(" & aCell & ",8,LEN(" & aCell & ")-12))&CHAR(32)&" & dCell & "&" & eCell & ")"
This seems to work for the first three example formula.
I'll leave it to you to translate the remaining 2 formula to VBA, which you should be able to do following my examples :)
Option Explicit
Sub foo()
Dim rng As Range, aCell As Range
Dim val As String
Set rng = Range("B1:B5") '## Modify the input range as needed.
For Each aCell In rng.Cells
Select Case Len(aCell)
Case 12
val = "S-" & Left(aCell, Len(aCell) - 9) & "-" & Mid(aCell, 4, Len(aCell) - 8)
Case 13
val = "S-" & Left(aCell, Len(aCell) - 10) & "-" & Mid(aCell, 4, Len(aCell) - 9)
Case 15
val = "SD-" & Mid(aCell, 5, Len(aCell) - 12) & "-" & Mid(aCell, 8, Len(aCell) - 12)
Case 16
val = "REF-" '## Modify as needed
Case 17
val = "REF-" '## Modify as needed
Case Else
'maybe warn the user this input is not anticipated...
MsgBox "Unsupported length!", vbInformation
End Select
val = UCase(val)
'## Append the values from column D,E:
val = val & " " & aCell.Offset(, 2) & aCell.Offset(, 3)
'## Write out to the workbook in column F, modify the "5" to specify a different location if needed e.g., "-1" would put it in column A, "0" would put in same column B, etc.
aCell.Offset(, 4).Value = val
Next
End Sub
I am essentially trying to match a series of cells from 2 worksheets and obtained values from a corresponding column.
When I run this code, I get an error:
object doesn't support this property or method
My Code
Sub Macro2()
Dim rowcount As Integer
Dim target As Variant
rowcount = Range("E2", Range("E2").End(xlDown)).Count
For i = 1 To rowcount + 1
target = Application.Match(ActiveSheet.Cells(i, 6) & "-" & Cells(i, 5) & "-" & Cells(i, 4) & "-" & Cells(i, 3), Worksheets(14).Range("A6:A3000"), 0)
If ActiveSheet.Cells(i, 6) & "-" & Cells(i, 5) & "-" & Cells(i, 4) & "-" & Cells(i, 3) = _
ActiveSheet.Cells(i + 1, 6) & "-" & Cells(i + 1, 5) & "-" & Cells(i + 1, 4) & "-" & Cells(i + 1, 3) Then
ActiveSheet.Cells(i, 17) = Worksheets(14).target.Offset(0, 10)
End If
Next i
End Sub
If you want to find the Row count, you need to use the syntax:
rowcount = Range(Range("E2"), Range("E2").End(xlDown)).Rows.Count , also it's better to use Long than Integer.
Also, you need to trap a possible error when unable to find a successful match with the Application.Match function, do it by using If Not IsError(target) Then.
Note: try to avoid using ActiveSheet, instead use fully qualified worksheet, by using Worksheets("YourSheetName") in your code.
Code
Sub Macro2()
Dim rowcount As Long
Dim target As Variant
rowcount = Range(Range("E2"), Range("E2").End(xlDown)).Rows.Count
For i = 1 To rowcount + 1
target = Application.Match(ActiveSheet.Cells(i, 6) & "-" & Cells(i, 5) & "-" & Cells(i, 4) & "-" & Cells(i, 3), Worksheets(14).Range("A6:A3000"), 0)
If Not IsError(target) Then ' successful Match
If ActiveSheet.Cells(i, 6) & "-" & Cells(i, 5) & "-" & Cells(i, 4) & "-" & Cells(i, 3) = _
ActiveSheet.Cells(i + 1, 6) & "-" & Cells(i + 1, 5) & "-" & Cells(i + 1, 4) & "-" & Cells(i + 1, 3) Then
ActiveSheet.Cells(i, 17) = Worksheets(14).target.Offset(0, 10)
End If
Else
MsgBox "Unable to find a Match !"
End If
Next i
End Sub
target is not a Property or Method of a Worksheets object.
I believe you need to change Worksheets(14).target.Offset(0, 10) to Worksheets(14).Range("A5").Offset(target, 10).
You should also be consistent in your coding. In your code you have things like ActiveSheet.Cells(i + 1, 6) & "-" & Cells(i + 1, 5) ..., where you specifically qualify Cells(i + 1, 6) to be on ActiveSheet but allow Cells(i + 1, 5) to default to being on the ActiveSheet. Although it works, it will get very confusing if you ever need to reread your code later on.
I have some code that searches a column of values in sheet(3) in the format of a string "value1 - value 2"
value2 is the first value in a column in sheet(2) and value1 is a value in the same column, in a cell further down the sheet.
The setup I have is:
In sheet(1), cells C2:C6 have values a-e respectively
In sheet(2), cell C1 has value "yes" and cells C2:C6 have values 1-5
respectively
In sheet(3), cell A2 has the value "4 - yes"
So the code should countif a column in sheet2 with the first value being yes and look for cells with the value 4, and put the result in cell B2 on sheet(3)
What it actually does is find the yes column (column C) and search the same column on sheet(1) (so the message boxes show letters rather than numbers).
Is there a way I can more precisely specify the sheet the countif function uses?
I'm using Excel 2000 on Windows 7
Private Sub test_click()
scenario_count = 6
Dim i As Integer
i = 1
Sheets(2).Select
For j = 2 To 24
If Sheets(2).Cells(1, j).Value = Right(Sheets(3).Cells(i + 1, 1).Value, Len(Sheets(3).Cells(i + 1, 1).Value) - InStrRev(Sheets(3).Cells(i + 1, 1).Value, "-") - 1) Then
MsgBox ("number of scenarios is " & scenario_count)
MsgBox ("value searching for is " & "'" & Left(Sheets(3).Cells(i + 1, 1).Value, InStrRev(Sheets(3).Cells(i + 1, 1).Value, "-") - 2) & "'")
MsgBox ("Range searched is " & Range(Cells(2, j), Cells(scenario_count, j)).Address & " in " & ActiveSheet.Name)
MsgBox ("Number of occurrences " & Sheets(2).Application.WorksheetFunction.CountIf(Range(Cells(2, j), Cells(scenario_count, j)), Left(Sheets(3).Cells(i + 1, 1).Value, InStrRev(Sheets(3).Cells(i + 1, 1).Value, "-") - 2)))
Sheets(2).Select
Sheets(3).Cells(i + 1, 2).Value = Sheets(2).Application.WorksheetFunction.CountIf(Range(Cells(2, j), Cells(scenario_count, j)), Left(Sheets(3).Cells(i + 1, 1).Value, InStrRev(Sheets(3).Cells(i + 1, 1).Value, "-") - 2))
For Each c In Range(Cells(2, j), Cells(scenario_count, j))
MsgBox ("comparing " & c.Address & " " & c.Value & " with " & Left(Sheets(3).Cells(i + 1, 1).Value, InStrRev(Sheets(3).Cells(i + 1, 1).Value, "-") - 2))
Next c
GoTo endofif2
End If
Next
endofif2:
End Sub
Where you have 'WorksheetFunction.CountIf(Range(Cells(2, j)', simply insert the sheet before the range reference, like so:
Sheets(2).Range(Sheets(2).Cells(2, j), Sheets(2).Cells(scenario_count, j))
EDIT full formula which references the sheet for both the Cells and the Range functions blatently taken from #Rory's comment.
I'm trying to make an automated templated with VBA and this code seems to run fine when I enter in a low number of "pages", but when I enter in something such as the following into the prompts it gives me a run-time error 1004: 14 pages: 41, 26, 19, 28, 26, 28, 17, 26, 21, 19, 19, 10, 23, 28.
Public TitleSize As Integer
Public MostValves() As Integer
Public TotalValves As Integer
Public TitleBlockSize As Integer
Function ConvertToLetter(iCol As Integer) As String
Dim iAlpha As Integer
Dim iRemainder As Integer
iAlpha = Int(iCol / 27)
iRemainder = iCol - (iAlpha * 26)
If iAlpha > 0 Then
ConvertToLetter = Chr(iAlpha + 64)
End If
If iRemainder > 0 Then
ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64)
End If
End Function
Sub ManualValve()
'On Error GoTo ErrHandler
'On Error Resume Next
Worksheets(1).Activate
ActiveSheet.Name = "Valve List"
ActiveSheet.Cells.Clear
PnIDPage = InputBox("How many pages are on your P&ID?")
'Values for Number of Pages: 14
Dim i As Integer
TotalValves = 0
ReDim MostValves(PnIDPage)
For i = 0 To PnIDPage - 1
ValveCount = InputBox("How many valves are on page " & i + 1 & " ?")
'Values for valves: 41, 26, 19, 28, 26, 28, 17, 26, 21, 19, 19, 10, 23, 28
If IsNumeric(ValveCount) Then
MostValves(i) = ValveCount
TotalValves = TotalValves + ValveCount
Else
MsgBox ("You did not enter a valid number")
'GoTo ErrHandler
End If
Next i
Dim Title As Variant
Response = MsgBox(prompt:="Do you want to use the default titleblock? (Count, Valve, Module, Note)", Buttons:=vbYesNo)
If Response = vbYes Then
Title = Array("Count", "Valve", "Module", "Note")
TitleSize = UBound(Title, 1) - LBound(Title, 1) + 1
Else
Title = Array("Count", "Valve", "Module")
TitleSize1 = UBound(Title, 1) - LBound(Title, 1) + 1
XtraCol = InputBox("How many extra columns would you like to add?")
ReDim Preserve Title(XtraCol + TitleSize1 - 1)
TitleSize = UBound(Title, 1) - LBound(Title, 1) + 1
For i = TitleSize1 + 1 To TitleSize
XtraTitle = InputBox("Extra Title " & i & "?")
Title(i - 1) = XtraTitle
Next i
End If
Dim TitleBlock As Variant
TitleBlock = Array("Project Number", "Project Name", "By", "Rev", "Date")
TitleBlockSize = UBound(TitleBlock, 1) - LBound(TitleBlock, 1) + 1
Range(ConvertToLetter(1) & "1:" & ConvertToLetter(1) & TitleBlockSize) = Application.Transpose(TitleBlock)
Dim Maximum As Integer
Dim ValveNum() As Integer
Dim TempSize As Integer
TempSize = 1
Maximum = WorksheetFunction.Max(MostValves) + 1
For i = 0 To PnIDPage - 1
Do Until MostValves(i) <> 0
i = i + 1
Loop
ReDim ValveNum(MostValves(i))
For j = 0 To MostValves(i)
ValveNum(j) = j + 1
Next j
MsgBox TempSize
If i Mod 2 = 0 Then
Worksheets(1).Range(ConvertToLetter(TempSize) & TitleBlockSize + 2 & ":" & ConvertToLetter(TempSize + TitleSize - 1) & Maximum + TitleBlockSize).Interior.ColorIndex = 42
Else
'This is where I encounter the run-time error
Worksheets(1).Range(ConvertToLetter(TempSize) & TitleBlockSize + 2 & ":" & ConvertToLetter(TempSize + TitleSize - 1) & Maximum + TitleBlockSize).Interior.ColorIndex = 43
End If
Worksheets(1).Range(ConvertToLetter(TempSize) & TitleBlockSize + 2 & ":" & ConvertToLetter(TempSize) & CStr(MostValves(i) + 1 + TitleBlockSize)). _
Resize(MostValves(i), 1) = Application.Transpose(ValveNum)
Worksheets(1).Range(ConvertToLetter(TempSize + 2) & TitleBlockSize + 2 & ":" & ConvertToLetter(TempSize + 2) & CStr(MostValves(i) + 1 + TitleBlockSize)) = "00" & CStr(i + 1)
Worksheets(1).Range(ConvertToLetter(TempSize) & TitleBlockSize + 1 & ":" & ConvertToLetter(TempSize + TitleSize - 1) & TitleBlockSize + 1) = Title
TempSize = TempSize + TitleSize
Worksheets(1).Range(ConvertToLetter(TempSize - 1) & TitleBlockSize + 1 & ":" & ConvertToLetter(TempSize - 1) & Maximum + TitleBlockSize). _
Borders(xlEdgeRight).Weight = xlMedium
Next i
Cells(1, 4) = "Total Valve Count"
Cells(1, 5) = TotalValves
Range("A1:" & ConvertToLetter(TempSize) & Maximum + TitleBlockSize).HorizontalAlignment = xlCenter
Range("A1:A" & TitleBlockSize).HorizontalAlignment = xlLeft
Columns("A:" & ConvertToLetter(TempSize)).AutoFit
Range("A1:" & ConvertToLetter(TempSize) & TitleBlockSize + 1).Font.Bold = True
Range("A" & TitleBlockSize + 1 & ":" & ConvertToLetter(TempSize - 1) & TitleBlockSize + 1).Interior.ColorIndex = 1
Range("A" & TitleBlockSize + 1 & ":" & ConvertToLetter(TempSize - 1) & TitleBlockSize + 1).Font.Color = vbWhite
Range("A" & Maximum + TitleBlockSize & ":" & ConvertToLetter(TempSize - 1) & Maximum + TitleBlockSize). _
Borders(xlEdgeBottom).Weight = xlMedium
'ErrHandler:
'MsgBox "An error has occurred. The macro will end."
End Sub
The problem does not depend on your Valve, but on your ConvertToLetter function. In fact, at some point the error occurs because the function returns an invalid range letter:
input: iCol = 53
return: "A["
Clearly, when you try to call the Range("A[2"), this raises the exception.
The code inside your function is not solid because converts the number into letter with:
ConvertToLetter = Chr(iAlpha + 64)
The Chr() function returns the value associated to the index from the characters collection, which is a unique chars list and cannot be used as you try to do there.
I would just replace your ConvertToLetter function with a more solid one, such as the following:
Function ConvertToLetter(iCol As Integer) As String
Dim vArr
vArr = Split(Cells(1, iCol).Address(True, False), "$")
ConvertToLetter = vArr(0)
End Function
...which has been kindly provided by brettdj in one of his precious answers (don't forget to give him an upvote for this piece of gold ;).
P.s. note that this explain also why a low number would not raise the exception: as long as the number is small, your function doesn't need to append a second letter to the output so it remains consistent. But as soon as it has to do that, CRASH ;)
Use the above function, it's way safer because it just retrieves the Range address from the Cells object. Your code will work fine once you will replace your old function with the new one above.
I have a report where I'm trying to get the sum of a dynamic number of rows in order to produce a subtotal.
If Cells(s, 1).Value = "start" Then
If Cells(r, 1).Value = "subtotal" Then
'Set the Monthly Subtotal Formulas
Cells(r, 44) = "=SUM(AR" & Trim(Str(s)) & ":AR" & Trim(Str(r - 1)) & ")"
Cells(r, 46) = "=SUM(AT" & Trim(Str(s)) & ":AT" & Trim(Str(r - 1)) & ")"
'Set the Weekly Subtotal Formulas
Cells(r, 48) = "=SUM(AV" & Trim(Str(s)) & ":AV" & Trim(Str(r - 1)) & ")"
Cells(r, 52) = "=SUM(AZ" & Trim(Str(s)) & ":AZ" & Trim(Str(r - 1)) & ")"
'Set the Daily Subtotal Formulas
Cells(r, 54) = "=SUM(BB" & Trim(Str(s)) & ":BB" & Trim(Str(r - 1)) & ")"
Cells(r, 56) = "=SUM(BD" & Trim(Str(s)) & ":BD" & Trim(Str(r - 1)) & ")"
'Set the Hourly Formulas
Cells(r, 60) = "=SUM(BH" & Trim(Str(s)) & ":BH" & Trim(Str(r - 1)) & ")"
Cells(r, 62) = "=SUM(BJ" & Trim(Str(s)) & ":BJ" & Trim(Str(r - 1)) & ")"
Cells(r, 1) = ""
End If
Cells(s, 1) = ""
End If
Basically, each work group is within the cell values "start" and "subtotal".
How can I find the 's' or row number and use that in the formula?
most of the time, built-in subtotals feature of Excel should be sufficient
in case you really need to use VBA solution and don't know how to iterate it over all "subtotal" tags already present in the data, place your code inside a loop like this:
header_column = Intersect(ActiveSheet.Range("A:A"), ActiveSheet.UsedRange).Value2
s = 1
For r = 1 To UBound(header_column)
If header_column(r, 1) = "start" Then
s = r
End If
If header_column(r, 1) = "subtotal" Then
' ... do your stuff here ... '
' s = r ' if the next "start" tag always follows a subtotal tag, no need for the "start" tags at all, just uncomment this line just before End If
End If
Next
P.S.: no need for "string" & Trim(Str(integer)), use "string" & integer instead