How to loop rows with Excel VBA macro? - vba

I am new to VBA, but pretty good with PHP. That being said, I'm struggling with VBA loops...
I have this sheet with 40 rows called "SH1":
SH1
A B C D E
1 2 One 1.0a 12
2 7 Two 2.0b 34
3 13 Three 3.0c 56
4 14 Four 4.0d 78
..
40
I need to loop through 40 rows and check the value in column A. If the value in column A meets my criteria (see below), generate some output and put it in another sheet.
My output sheet is 3-columns and called "SH2":
SH2
A B C D E
1 1.0a 12 One
2.0b 34 Two
2 3.0c 56 Three
4.0d 78 Four
..
15
My criteria for deciding what goes where:
// First loop:
if a1 < 8, put c1 in SH2 a1, put d1 in SH2 b1, put b1 in SH2 c1
if a2 < 8, put c2 in SH2 a1, put d2 in SH2 b1, put b2 in SH2 c1
// ... loop through a40 ...
Then:
// Second loop:
if a1 > 8 AND a1 < 16, put c1 in SH2 a2, put d1 in SH2 b2, put b1 in SH2 c2
if a2 > 8 AND a2 < 16, put c2 in SH2 a2, put d2 in SH2 b2, put b2 in SH2 c2
// ... loop through a40 ...
PROGRESS EDIT:
Seems to be working, but wondering if there is a "cleaner" way?
Sub CatchersPick2()
Dim curCell As Range
For Each curCell In Sheet4.Range("C3:C40").Cells
If curCell.Value > 0 And curCell.Value < 73 Then
cLeft = cLeft _
& curCell.Offset(0, 5) & "." _
& curCell.Offset(0, 6) & vbLf
cMidl = cMidl _
& curCell.Offset(0, -2) & ", " _
& curCell.Offset(0, -1) & " " _
& curCell.Offset(0, 7) & vbLf
cRght = cRght _
& curCell.Offset(0, 9) & " " _
& curCell.Offset(0, 2) & " " _
& curCell.Offset(0, 11) & " " _
& curCell.Offset(0, 10) & vbLf
End If
Next curCell
Sheet6.Range("B3") = cLeft
Sheet6.Range("C3") = cMidl
Sheet6.Range("D3") = cRght
Sheet6.Range("B3:D3").Rows.AutoFit
Sheet6.Range("B3:D3").Columns.AutoFit
End Sub

Dim cell As Range
For Each cell In Range("a1:a40")
'do stuff here
Next cell
You can get your current row with cell.Row. Good luck ^_^

How about:
Sub Catchers()
Dim cell As Range
Sheet1.Select 'SHEET: C
For Each cell In Range("C3:C40")
If cell.Value < 35 And cell.Value > 0 Then
With Sheet6
.Range("B" & cell.Row) = cell.Offset(0, 5) _
& "." & cell.Offset(0, 6)
.Range("C" & cell.Row) = cell.Offset(0, -2) _
& ", " & cell.Offset(0, -1) _
& " " & cell.Offset(0, 7)
.Range("D" & cell.Row) = cell.Offset(0, 9) _
& " " & cell.Offset(0, 2) _
& " " & cell.Offset(0, 11) _
& " " & cell.Offset(0, 10)
End With
End If
Next cell
Sheet6.Range("B4:D4").Rows.AutoFit
Sheet6.Range("B4:D4").Columns.AutoFit
End Sub

There's not a lot you can do, but...
First, don't use the word 'cell' as a variable, it may work, but it's playing with fire, so
Dim curCell as Range
Second, you should loop through the Cells property of the Range
For Each curCell In Range("C3:C40").Cells
Third, you don't need to Select the cell, you can just manipulate the curCell variable
Lastly, you won't need to use ActiveCell, just use the curCell variable.
If curCell.Value < 35 And curCell.Value > 0 Then
cLefta = curCell.Offset(0, 5) & "."
In fact, you could also just use a short variable like 'c' and put the whole thing on one line:
cLeft = c.Offset(0,5) & "." & c.Offset(0,6) & vblf
Note: If your setup is close to the same every time, it would probably be easier to just use worksheet-functions.

Related

For loop with formulas

I have this code below which I want to be used in a loop. However, instead of C5 and D5, I would want this loop to be run on all the cells in column C and column D and not only for C5 and D5.
To summarize, I would want C5 and D5 to be replaced by every cell in Column C and D. Please assist.
For i = 1 To 5
Valuex = Evaluate("=IsNumber(Value(Mid(C5, 2, 1)))")
MsgBox (Valuex)
Valuex1 = Evaluate("=Left(Trim(C5), 1) = ""R""")
MsgBox (Valuex1)
If ((Evaluate("=Left(Trim(C5), 1) = ""R""") = "True") And (Evaluate("=IsNumber(Value(Mid(C5, 2, 1)))") = "True")) Then
Range("D5").Formula = "=VLOOKUP(C5,[old.xls]Sheet1!$D:$V,19,0)"
MsgBox ("if")
Else
Range("D5").Formula = "=VLOOKUP(C5,[old.xls]Sheet1!$E:$V,18,0)"
MsgBox ("else")
End If
Next i
Think this does what you want. It will run from row 1 to the last row in C. Note that you could do all this without VBA.
Sub x()
Dim i As Long, Valuex As Boolean, Valuex1 As Boolean
For i = 1 To Range("C" & Rows.Count).End(xlUp).Row
Valuex = Evaluate("=IsNumber(Value(Mid(C" & i & ", 2, 1)))")
MsgBox (Valuex)
Valuex1 = Evaluate("=Left(Trim(C" & i & "), 1) = ""R""")
MsgBox (Valuex1)
If Valuex1 And Valuex Then
Range("D" & i).Formula = "=VLOOKUP(C" & i & ",[old.xls]Sheet1!$D:$V,19,0)"
MsgBox ("if")
Else
Range("D" & i).Formula = "=VLOOKUP(C" & i & ",[old.xls]Sheet1!$E:$V,18,0)"
MsgBox ("else")
End If
Next i
End Sub
I think you can avoid the loop altogether thus
Sub xx()
Dim i As Long
i = Range("C" & Rows.Count).End(xlUp).Row
With Range("D1:D" & i)
.Formula = "=IF(AND(ISNUMBER(VALUE(MID(C1, 2, 1))),LEFT(TRIM(C1), 1) = ""R""),VLOOKUP(C1,Sheet1!$D:$V,19,0),VLOOKUP(C1,Sheet1!$E:$V,18,0))"
.Value = .Value
End With
End Sub

5 if statement formula

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

Correcting formula in vba excel

I want to create a macro that check all the cells of a column and if the first two characters of a cell is "BB" then i want the macro to extract three characters from the cell and paste it to the next column but a the corresponding row.
But my formula after the if clause is not working.
this is what i have done since:
Sub test()
Dim lmid As String
Dim srange, SelData, ExtBbFor As String
Dim lastrow As Long
Dim i, icount As Integer
lastrow = ActiveSheet.Range("B30000").End(xlUp).Row
srange = "G1:G" & lastrow
SelData = "A1:G" & lastrow
Range(srange).Formula = "=mid(E1,1,3)"
For i = 1 To lastrow
If InStr(1, LCase(Range("E" & i)), "bb") <> 0 Then
Range("G" & i).Formula = "=mid("E & i", 4, 3)"
End If
Next i
End Sub
thanks in advance
Try with below. It will work
Range("G" & i).Value = Mid(Range("E" & i), 4, 3)
If the cell is not limited to 7 then you need as below
Range("G" & i).Value = "=Mid(E" & i & ", 3, " & Len(E & "& i & ") & ")"
It will extract from the 3rd character up to the last character in a cell.
Your syntax is wrong where you're trying to concatenate strings, I think you mean to use:
Range("G" & i).Formula = "=MID(E" & i & ",4,3)"
Based on your code I think this will do the exact same thing without having to loop or declare any variables:
Sub test()
With Range("G1:G" & Cells(Rows.Count, 2).End(xlUp).Row)
.FormulaR1C1 = "=IF(UPPER(LEFT(RC[-2],2))=""BB"",MID(RC[-2],4,3),"""")"
.Value = .Value
End With
End Sub

How to dynamically change range inside formula?

I’m applying a formula:
Textual representation of formula:
=(SUBSTITUTE((LEFT(A2;(FIND("htt";A2;1))-3));";";";"))&RIGHT(A2;(LEN(A2)-(FIND("htt";A2;1))+3))
to all cells in a range A2:A10, writing a result to range B2:B10 respectively.
To do this I use the following macro:
Sub ColumnsFormat()
Dim s As String
Dim i As Integer, j As Integer
'Set wb = Workbooks("CSV_File.xlsm")
Application.ScreenUpdating = False
j = 1
For i = 2 To 10
s = "=(SUBSTITUTE((LEFT(R[" & Trim(Str(i)) & "]C[" & Trim(Str(j - 2)) & "],(FIND(""htt"",R[" & Trim(Str(i)) & "]C[" & Trim(Str(j - 2)) & "],1))-3)),"","","";""))&RIGHT(R[" & Trim(Str(i)) & "]C[" & Trim(Str(j - 2)) & "],(LEN(R[" & Trim(Str(i)) & "]C[" & Trim(Str(j - 2)) & "])-(FIND(""htt"",R[" & Trim(Str(i)) & "]C[" & Trim(Str(j - 2)) & "],1))+3))"
Sheets("Sheet1").Cells(i, 2).Value = s
Next i
End Sub
The problem is that for some reason a row number inside the formula inside a For cycle is wrong. Instead of taking A2; A3; A4 … A10 cells, (changing row number by 1 each time), macro runs through A2; A4; A6 etc. (increasing a row number by 2 each time).
What am I doing wrong?
By changing the row in the formula to 0 the code works just fine. I guess the problem is that in your formula the row was calculated relative to the specific cell the formula was afterwards applied to. Therefore the formula in B2 looked at A(2+2), in B3 at A(3+3) and so on.
Sub ColumnsFormat()
Dim s As String
Dim i As Integer, j As Integer
'Set wb = Workbooks("CSV_File.xlsm")
Application.ScreenUpdating = False
j = 1
For i = 2 To 10
s = "=(SUBSTITUTE((LEFT(R[" & 0 & "]C[" & j - 2 & "],(FIND(""htt"",R[" & 0 & "]C[" & Trim(Str(j - 2)) & "],1))-3)),"","","";""))&RIGHT(R[" & 0 & "]C[" & Trim(Str(j - 2)) & "],(LEN(R[" & 0 & "]C[" & Trim(Str(j - 2)) & "])-(FIND(""htt"",R[" & 0 & "]C[" & Trim(Str(j - 2)) & "],1))+3))"
Sheets("Sheet1").Cells(i, 2).Value = s
Next i
End Sub

Convert 'yyyymmdd hhmmss' to 'mm/dd/yy hh:mm'

I have a row of data (Cell A3 and down) that contains a Unix timestamp in yyyymmdd hhmmss format that I'm trying to convert to mm/dd/yy hh:mm format automatically.
The code I have so far works when I have the data starting in cell A1, but I need A1 to remain blank, therefore the data starts at A2. Here is an example screenshot of column A:
Sub auto_open()
'
' auto_open Macro
'
'
ChDir "C:\"
Workbooks.Open Filename:="C:\Users\username\Desktop\file1.csv"
Intersect(Sheets("file1").Range("A:EW"), Sheets("file1").UsedRange).Copy ThisWorkbook.Sheets("Golden").Range("A2")
Windows("file1.csv").Activate
Application.CutCopyMode = False
ActiveWorkbook.Close SaveChanges = False
Dim x As Integer
Dim y As String
Dim z As String
Dim w As String
NumRows = Range("A3").End(xlDown).Row
Windows(ThisWorkbook.Name).Activate
For x = 2 To NumRows
z = Cells(x, 1).Value
y = Mid(z, 5, 2) & "/" & Mid(z, 7, 2) & "/" & Left(z, 4)
w = Mid(z, 10, 2) & ":" & Mid(z, 12, 2) & ":" & Mid(z, 14, 2)
y = y + TimeValue(w)
Cells(x, 1).Value = y
Next x
Range("A3").Select
End Sub
It errors whether I set the range to A2 or A3 and down.
Does anyone have recommendations?
Debug highlights y = Mid(z, 5, 2) & "/" & Mid(z, 7, 2) & "/" & Left(z, 4) but I'm not sure what the problem is.
Format cells (custom > mm/dd/yyyy hh:mm:ss) also does not work in my case, unfortunately.
This will do it with no looping at all:
Sub kyle()
With [a3].Resize([a1048576].End(xlUp).Row - 2)
.Value = Evaluate("transpose(transpose(DATE(MID(" & .Address & ",1,4),MID(" & .Address & ",5,2),MID(" & .Address & ",7,2)) + TIME(MID(" & .Address & ",10,2),MID(" & .Address & ",12,2),MID(" & .Address & ",14,2))))")
End With
End Sub
Note: you can then use whatever number formatting for the dates you please.
Try this:
Sub Kyle()
Dim cell As Range
ThisWorkbook.Activate
For Each cell In Range("A2", Cells(Rows.Count, "A").End(xlUp))
If cell.Value Like "######## ######" Then
cell.Value = CDate(Format(cell.Value, "####-##-#####:##:##"))
End If
Next cell
End Sub
Then format the column however you prefer.
For me, that converts
20150904 213613
20150124 194003
20150404 163056
20151220 100509
20150510 213512
to this:
09/04/2015 21:36
01/24/2015 19:40
04/04/2015 16:30
12/20/2015 10:05
05/10/2015 21:35
#ExcelHero answered my question via email. The following is the working code for anyone who needs future reference.
With [a3].Resize([a65536].End(xlUp).Row - 2)
If Len(.Item(1)) = 15 Then
.Value = Evaluate("transpose(transpose(DATE(MID(" & .Address & ",1,4),MID(" & .Address & ",5,2),MID(" & .Address & ",7,2)) + TIME(MID(" & .Address & ",10,2),MID(" & .Address & ",12,2),MID(" & .Address & ",14,2))))")
End If
.NumberFormat = "mm/dd/yyyy hh:mm"
End With