I am trying to loop through an array and, when it finds a cell which is not equal a specific value, it deletes the entire row. Here is the code:
Sub DeleteTest()
Dim crr()
crr = Range("A3:A1000")
For i = LBound(crr, 1) To UBound(crr, 1)
If (crr(i, 1) <> "One" And crr(i, 1) <> "Two") Then
' Line to delete the row in which the value of the cell is not One or Two
End If
Next
End Sub
I know I can also do it with an Autofilter, but I would like to know the way to do it with the array.
Here's one way:
Sub DeleteTest()
Dim rng As Range, crr(), i As Long
Set rng = Range("A3:A1000")
crr = rng.Value
For i = UBound(crr, 1) To LBound(crr, 1) Step -1 '<<< loop backwards
If (crr(i, 1) <> "One" And crr(i, 1) <> "Two") Then
rng.Cells(i).EntireRow.Delete
End If
Next
End Sub
Try this code
Sub Test()
Dim x, r As Range
With ThisWorkbook.Sheets("Sheet1")
Set r = .Range("A3:A1000")
x = Filter(.Evaluate("TRANSPOSE(IF((" & r.Address & "=""One"")+(" & r.Address & "=""Two""),""A"" & ROW(" & r.Address & ")))"), False, False)
If UBound(x) = -1 Then Exit Sub
.Range(Join(x, ",")).EntireRow.Hidden = True
On Error Resume Next
r.SpecialCells(xlCellTypeVisible).EntireRow.Delete
On Error GoTo 0
.Rows.Hidden = False
End With
End Sub
Looking for the VBA to produce this result in a column of a sheet:
1.000000
1.000001
1.000002
…
…
1.001000
1.001001
1.001002
It can be text or number.
Thanks.
Hopefully this is a good starting point:
Sub foo()
Dim lngCount As Long
With Sheet1
For lngCount = 1 To 1002
.Range("A" & lngCount).NumberFormat = "0.000000"
.Range("A" & lngCount).Value = 1 + ((lngCount - 1) / 1000000)
Next lngCount
End With
End Sub
This would be especially suitable for a function
Public Function replacechar(str As String, charnumber As Integer, replacewith As String) As String
Dim startstr As String, endstr As String
startstr = Left(str, charnumber-1)
endstr = Right(str, Len(str) - Len(startstr))
replacechar = startstr & replacewith & endstr
End Function
You can call this function in a regular Sub, for example
Sub repl()
Dim newstr As String, c As Range
With ThisWorkbook.Sheets(1)
For Each c In .Range("A1:A100")
If not c.Value = "" Or Len(c.Value) < 5 Then
newstr = replacechar(c.Value, 5, "1") 'replaces the 5th char with "1"
c.Value = newstr
End If
Next c
End With
End Sub
This can done using NumberFormat and a Formula. the .Value2 = .Value2 converts the formula to an actual value
' Update ActiveSheet with your destination sheet reference
' Update .Cells(1,1) with reference to your starting cell - This is A1
' Update Resize(xxx) with the number of cells you want populated
With ActiveSheet.Cells(1, 1).Resize(100)
.NumberFormat = "0.000000"
.Formula = "=1 + (row()" & IIf(.Cells(1).Row > 1, " - " & .Cells(1).Row, "") & ") / 1e6"
.Value2 = .Value2
End With
Why is my first iteration in Sub throughCols that is intended to move one row down each time jumping four rows?
Option Explicit
Dim txt As String
Dim i As Long
Dim strTest As String
Dim strArray() As String
Dim lCaseOn As Boolean
Dim firstRow As Long, startIt As Long
Dim thisCell As Range
Dim lastRow As Long
Dim resetAddress As Range
Sub throughCols()
' Dim thisCell As Range
' get start and end of column data
' NB sheet name is hard coded twice
Call dataRange
startIt = firstRow + 1
For i = 1 To 8 Step 1
' after testing use startIt To lastRow Step 1
' by using activeCell I dont have to pass range through to the sub
Sheets("test").Range("B" & i).Select
MsgBox "this is itteration " & i & " which will output to " & ActiveCell.Offset(0, 2).Address
Call arrayManip
Call cleanTxt(txt)
Next i
End Sub
Sub arrayManip()
' clear out all data
Erase strArray
txt = ""
'set default case
lCaseOn = False
' string into an array using a " " separator
strTest = WorksheetFunction.Proper(ActiveCell.Value)
strTest = Replace(strTest, "-", " - ")
strTest = Replace(strTest, "‘", " ‘ ")
strArray = Split(strTest, " ")
' itterate through array looking to make text formats
For i = LBound(strArray) To UBound(strArray)
If strArray(i) = "-" Then
lCaseOn = True
GoTo NextIteration
End If
If strArray(i) = "‘" Then
lCaseOn = True
GoTo NextIteration
End If
If lCaseOn Then
strArray(i) = LCase(strArray(i))
lCaseOn = False
NextIteration:
End If
Next
End Sub
Function cleanTxt(txt)
' loop through the array to build up a text string
For i = LBound(strArray) To UBound(strArray)
txt = txt & strArray(i) & " "
Next i
' remove the space
txt = Trim(Replace(txt, " - ", "-"))
txt = Trim(Replace(txt, " ‘ ", "‘"))
' MsgBox "active cell is " & activeCell.Address
ActiveCell.Offset(0, 2).Select: ActiveCell.Value = txt
' MsgBox "final output would be " & txt & " to " & activeCell.Address
' this is a thumb suck to attempt to reset the active cell to the itteration address that started it
ActiveCell.Offset(0, -2).Select
MsgBox "next itteration should start with active cell set as " & ActiveCell.Address
End Function
Sub dataRange()
With Sheets("test").Columns("B")
If WorksheetFunction.CountA(.Cells) = 0 Then '<--| if no data whatever
MsgBox "Sorry: no data"
Else
With .SpecialCells(xlCellTypeConstants) '<--| reference its cells with constant (i.e, not derived from formulas) values)
firstRow = .Areas(1).Row
lastRow = .Areas(.Areas.Count).Cells(.Areas(.Areas.Count).Rows.Count).Row
End With
' MsgBox "the first row is " & firstRow
' MsgBox "last row is " & lastRow
End If
End With
End Sub
You are declaring your i variable at module scope, which makes it accessible everywhere within the module; it's modified when you call arrayManip and the value changes.
If you declare a local ind variable inside this routine it won't happen, because the variable will only be accessible to the scope it's declared in. Try the code below:
Sub throughCols()
' Dim thisCell As Range
Dim ind As Long '<-- DECLARE local variable
' get start and end of column data
' NB sheet name is hard coded twice
Call dataRange
startIt = firstRow + 1
' ===== loop on ind and not i (changes when you call arrayManip) ====
For ind = 1 To 8 ' Step 1 <-- actually not needed, that's the default increment value
' after testing use startIt To lastRow Step 1
' by using activeCell I dont have to pass range through to the sub
Sheets("test").Range("B" & ind).Select
MsgBox "this is itteration " & ind & " which will output to " & ActiveCell.Offset(0, 2).Address
Call arrayManip
Call cleanTxt(txt)
Next ind
End Sub
First off thank you very much. Over the last few months (i believe) my coding has progressed drastically. Any and all criticize is always welcome (rip me apart).
Recently I started to try to use different Subs (I dont quite understand when to use functions etc, but i figure it is good structure practice for when i figure it out.
I am hitting a Run-time 424 Error with the following bit of code in Sub ownerCHECK
Sub OccupationNORMALIZATION()
Dim infoBX As String
' initialize variables
LRow = ActiveSheet.UsedRange.Rows.Count
LCol = ActiveSheet.UsedRange.Columns.Count
STATUScounter = LRow
Do While infoBX = ""
infoBX = InputBox("Enter Occupation Column", "Occupation Column")
Loop
restaurCHECK (infoBX)
Application.ScreenUpdating = True
Application.StatusBar = ""
End Sub
-
Sub restaurCHECK(infoBX As String)
Dim RestaurantS(), RestaurantDQs() As Variant
Dim i, LRow, LCol, STATUScounter As Long
Dim rRng As Range
LRow = ActiveSheet.UsedRange.Rows.Count
LCol = ActiveSheet.UsedRange.Columns.Count
STATUScounter = LRow
RestaurantS = Array("estaur", "food", "cafe", "beverage", "waiter", "waitr", _
"waitstaff", "wait staff", "grill") 'array list of target occupations
RestaurantDQs = Array("fast", "pub", "import", "packing", "processing", "packag", _
"retired", "anufact", "distrib") ' disqualifying words for Restaurante category
Set rRng = Range(infoBX & "2:" & infoBX & LRow)
Application.ScreenUpdating = False
For Each cell In rRng
ownerCHECK (cell)
For i = LBound(RestaurantS) To UBound(RestaurantS)
If InStrRev(cell.Value, UCase(RestaurantS(i))) > 0 Then
cell.Offset(, 1) = "Restaurants"
cell.Interior.Color = 52479
End If
Debug.Print cell.Value
Next
For i = LBound(RestaurantDQs) To UBound(RestaurantDQs)
If InStrRev(cell.Value, UCase(RestaurantDQs(i))) And cell.Interior.Color = 52479 Then
cell.Interior.Color = 255
cell.Offset(, 1) = ""
End If
Next
STATUScounter = STATUScounter - 1
Application.StatusBar = "REMAINING ROWS " & STATUScounter & " tristram "
Next cell
End Sub
-
Sub ownerCHECK(str_owner As Range)
Dim owner() As Variant
owner() = Array("owner", "shareholder", "owns ")
For i = LBound(owner) To UBound(owner)
If InStrRev(str_owner, UCase(owner(i))) > 0 Then
cell.Offset(, 2) = "Owner"
End If
Next
End Sub
I can see a couple of issues in ownerCHECK():
"cell" is not defined (unless it's global)
you shouldn't use "cell" as a variable name (internal VBA property)
check validity of incoming range
.
Option Explicit
Sub ownerCHECK(ByRef rngOwner As Range)
If Not rngOwner Is Nothing Then
Dim owner() As Variant
owner() = Array("OWNER", "SHAREHOLDER", "OWNS ")
For i = LBound(owner) To UBound(owner)
If InStrRev(UCase(rngOwner), owner(i)) > 0 Then
rngOwner.Offset(, 2) = "Owner"
End If
Next
End If
End Sub
I'm not entirely sure how to word this but, I have an Excel macro that enables a search functionality within my workbook. My issue is that I need the search to understand 'é' as 'e'. So that if I search for 'Belem', my result would come back with 'Belém'. How would I go about this? Thanks for any time and consideration.
Sub city()
If ActiveSheet.Name <> "City" Then Exit Sub
LastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Sheets("Results").Range("3:10000").Delete
SearchTerm = Application.InputBox("What are you looking for?")
Application.ScreenUpdating = False
Range("W1") = SearchTerm
Range("W2:W" & LastRow).FormulaR1C1 = _
"=IF(ISERR(SEARCH(R1C23,RC[-22]&RC[-21]&RC[-20]&RC[-19]&RC[-18]&RC[-17]&RC[-16]&RC[-15]&RC[-15]&RC[-14]&RC[-13]&RC[-12]&RC[-11]&RC[-10]&RC[-9]&RC[-8]&RC[-7]&RC[-6]&RC[-5]&RC[-4]&RC[-3]&RC[-2]&RC[-1])),0,1)"
If WorksheetFunction.CountIf(Columns(23), 1) = 0 Then
Columns(23).Delete
Application.ScreenUpdating = True
MsgBox "None found."
Else
For Each Cell In Range("A2:A" & LastRow)
If Cell.Offset(, 22) = 1 Then
Cell.Resize(, 51).Copy Sheets("Results").Range("A" & Rows.Count).End(xlUp).Offset(1)
x = x + 1
End If
Next Cell
Columns(22).Delete
Application.ScreenUpdating = True
If x = 1 Then
MsgBox "1 matching record was copied to Search Results tab."
Else
MsgBox x & " matching records were copied to Search Results tab."
End If
End If
End Sub
You can modify the search parameter and then use the like operator as follows:
Sub city()
Dim rngResult As Range
Dim searchTerm As String, counter As Integer
Dim values As Variant, value As Variant
If ActiveSheet.Name <> "City" Then Exit Sub
'First Cell with the results
Set rngResult = <First cell of the result Range>
'Uses a variant array to get all values from the range. This speeds up the routine
values = <Area of Search>.Value
'Converts to lowercase to do a case insensitive search (e.g. Belem = belem)
searchTerm = LCase(Application.InputBox("What are you looking for?"))
If searchTerm = "" Then Exit Sub
' "§" is just a placeholder
searchTerm = Replace(searchTerm, "e", "§")
searchTerm = Replace(searchTerm, "é", "§")
searchTerm = Replace(searchTerm, "§", "[eé]")
Application.ScreenUpdating = False
counter = 0
For Each value In values
If LCase(value) Like searchTerm Then
rngResult = value
Set rngResult = rngResult.Offset(1, 0) 'Moves to the next line
counter = counter + 1
End If
Next value
If counter = 0 Then
MsgBox "None found."
Else
MsgBox "Found " & counter & " results"
'Do what you need to do with the results
End If
Application.ScreenUpdating = True
End Sub
All the results will be at the column of rngResult.
The code works by replacing "e" and "é" by "§" and then replacing "§" by "[eé]", (e.g. "bélem" -> "bél§m" -> "b§l§m" -> "b[eé]l[eé]m").
The like will match either "e" or "é" on that position. You can learn more about it here or in the help files. Here is a Example:
bélem Like "b[eé]l[eé]m" ' true
belem like "b[eé]l[eé]m" ' true
recife like "b[eé]l[eé]m" ' false
You can search more graphs by adding other criteria like:
'Like will match "a","á", "à" and "ã"
searchTerm = Replace(searchTerm, "a", "§")
searchTerm = Replace(searchTerm, "á", "§")
searchTerm = Replace(searchTerm, "à", "§")
searchTerm = Replace(searchTerm, "ã", "§")
searchTerm = Replace(searchTerm, "§", "[aáàã]")
This method has the advantage that you only need one "translation" in order to do comparisons. This can improve the performance if you have a large dataset
You can keep an array of all the characters you want to replace and what you want to replace them with. It's easier if you "search" your data a little differently that using that formula. Here's how I would do it.
Sub FindCity()
Dim shResults As Worksheet
Dim vaData As Variant
Dim i As Long, j As Long
Dim sSearchTerm As String
Dim sData As String
Dim rNext As Range
'Put all the data into an array
vaData = ActiveSheet.UsedRange.Value
'Get the search therm
sSearchTerm = Application.InputBox("What are you looking for?")
'Define and clear the results sheet
Set shResults = ActiveWorkbook.Worksheets("Results")
shResults.Range("A3").Resize(shResults.UsedRange.Rows.Count, 1).EntireRow.Delete
'Loop through the data
For i = LBound(vaData, 1) To UBound(vaData, 1)
For j = LBound(vaData, 2) To UBound(vaData, 2)
'Get rid of diacritial characters
sData = LCase(Anglicize(vaData(i, j)))
'Look for a match
If InStr(1, sData, LCase(Anglicize(sSearchTerm))) > 0 Then
'Write the row to the next available row on Results
Set rNext = shResults.Cells(shResults.Rows.Count, 1).End(xlUp).Offset(1, 0)
rNext.Resize(1, UBound(vaData, 2)).Value = Application.Index(vaData, i, 0)
'Stop looking in that row after one match
Exit For
End If
Next j
Next i
End Sub
Public Function Anglicize(ByVal sInput As String) As String
Dim vaGood As Variant
Dim vaBad As Variant
Dim i As Long
Dim sReturn As String
'Replace any 'bad' characters with 'good' characters
vaGood = Split("S,Z,s,z,Y,A,A,A,A,A,A,C,E,E,E,E,I,I,I,I,D,N,O,O,O,O,O,U,U,U,U,Y,a,a,a,a,a,a,c,e,e,e,e,i,i,i,i,d,n,o,o,o,o,o,u,u,u,u,y,y", ",")
vaBad = Split("Š,Ž,š,ž,Ÿ,À,Á,Â,Ã,Ä,Å,Ç,È,É,Ê,Ë,Ì,Í,Î,Ï,Ð,Ñ,Ò,Ó,Ô,Õ,Ö,Ù,Ú,Û,Ü,Ý,à,á,â,ã,ä,å,ç,è,é,ê,ë,ì,í,î,ï,ð,ñ,ò,ó,ô,õ,ö,ù,ú,û,ü,ý,ÿ", ",")
sReturn = sInput
For i = LBound(vaBad) To UBound(vaBad)
sReturn = Replace$(sReturn, vaBad(i), vaGood(i))
Next i
Anglicize = sReturn
End Function
List of characters from Excel 2007 VBA Converting Accented Characters to Regular