Clear Constants in a range without clearing references and formulas - vba

I am trying to clear all the number constants in a range of cells without clearing any formulas or cell references. Clearing the constants from cells without any formulas or cell references is simple but I am having trouble doing it when those are present. Below is the code I have so far.
Range("B2:B11").Select
Selection.SpecialCells(xlCellTypeConstants, 1).Select
Selection.ClearContents
In this range cells B5 and B7 have formulas with cell references as follows:
B5: =(G83*H1)+1181.05
B7: =E33+1292.76
The cell references will also at times reference cells on other sheets in the same workbook. I need to clear the constants from these formulas while leaving the references intact.

This will remove constants from all formulas in current workbook based on 2 patterns:
"=Formula-[Space]-PlusSign-[Space]-Constant" (space optional)
=(G83*H1)+1181.05 or =(G83*H1) +1181.05 or =(G83*H1)+ 1181.05 becomes =(G83*H1)
=E33+1292.76 or =E33 +1292.76 or =E33+ 1292.76 or =E33 + 1292.76 becomes =E33
"=Formula-[Space]-MinusSign-[Space]-Constant" (space optional)
Public Sub clearConstantsFromWorkBookFormulas()
Const PATTERNS As String = "~+*|~+ *|~ +*| ~+ *|~-*|~- *|~ -*|~ - *"
Dim pat As Variant
For Each pat In Split(PATTERNS, "|")
Cells.Replace What:=pat, _
Replacement:=vbNullString, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False
Next
End Sub
.
This is a more generic option using regEx pattern matching and arrays:
Public Sub testClear()
Dim ws As Worksheet
For Each ws In Application.ActiveWorkbook.Worksheets
removeConstantsFromFormulas ws.Range("B2:B11"), getRegEx
Next
End Sub
Public Sub removeConstantsFromFormulas(ByRef rng As Range, ByRef regEx As Object)
Dim v As Variant, r As Long, c As Long, lr As Long, lc As Long
lr = rng.Rows.Count
lc = rng.Columns.Count
If lr > 0 And lc > 0 Then
v = rng.Formula
For r = 1 To lr
For c = 1 To lc
If Left(v(r, c), 1) = "=" Then
If regEx.Test(v(r, c)) Then v(r, c) = regEx.Replace(v(r, c), vbNullString)
End If
Next
Next
rng.Formula = v
End If
End Sub
Private Function getRegEx() As Object
Set getRegEx = CreateObject("VBScript.RegExp")
getRegEx.Pattern = "[^a-zA-Z][0-9]+(\.?[0-9]+)"
getRegEx.Global = True
getRegEx.IgnoreCase = True
End Function
RegEx pattern: one or more digits, digit group not preceded by a letter, with or without a fraction part

This attempt should handle most examples using a Regexp.
There may be some edge cases as the discussion above points out. For the code below
=(G83*H1)+1181.05
=10+A1
=A1+10
=A1+(10)
=A1+10.0
becomes
=(G83*H1)
=+A1
=A1
=A1
=A1
I note it would also take out the ^2 in =A1^2
It clearly also won't cater for named formulae (named ranges).
Updated: Now handles cascading parentheses, ie
=A1+(27+(11-2))
becomes
=A1
Sub Format()
Dim objRegexB As Object
Dim lngCnt As Long
Dim X
X = [b2:b11].Formula
Set RegExB = CreateObject("vbscript.regexp")
With RegExB
.Pattern = "[=\+\/\*^\-](\([0-9]\d*(\.\d+)?\)|[0-9]\d*(\.\d+)?|\.\d+)"
.Global = True
For lngCnt = 1 To UBound(X)
Do While .Test(X(lngCnt, 1))
X(lngCnt, 1) = .Replace(X(lngCnt, 1), vbNullString)
Loop
Next
End With
[b2:b11].Formula = X
End Sub

Related

Using cell reference formula in VBA to return cell to use in VBA code

I am trying to use a formula with INDEX and MATCH to return a cell reference to enter TEXT into with VBA.
I have a list of vendors in column A and to find the cell to the right of it I can use the following
=CELL("address";INDEX(A29:C42;MATCH("***";A29:A42;0);2))
However I am struggling with how to get this in my VBA code. (note the value *** is changing as I need to run the sub several times for different vendors.
Can i use Function sub for this? I have tried as below with no luck:
Sub CellRef()
'
' CellRef
'
'
Function.Range(="CELL("ADDRESS";INDEX(A29:C42;MATCH("Accenture";A29:A42;0);2))")
End Sub
If I understand your question correctly you want to match the value/vendor in column A and return the address of the cell to its right?
You can do like so:
Cell2WorkWith = Cells(Application.Match(Searchvalue, Searchrange, 0),2).Address
If you don't want the "$", then replace them like so:
Cell2WorkWith = Replace(Cells(Application.Match(Searchvalue, Searchrange, 0),2).Address,"$","")
Or, even better, like:
Cell2WorkWith = Cells(Application.Match(Searchvalue, Searchrange, 0),2).Address(0,0)
If I misunderstood and it is the value from that cell to the right then below will do:
Value2WorkWith = Cells(Application.Match(Searchvalue, Searchrange, 0),2).Value
Remember to only use match when the value CAN be found within the range, else you'll have to catch an error.
One alternative would be to look for the cell with "Find":
Option Explicit
Sub CellRef()
Dim SearchString As String
Dim ra, cell, VendorsRange As Range
Dim k As Integer
Set VendorsRange = Range("E1:E10")
k = 1
For Each cell In VendorsRange
SearchString = cell.Value
Set ra = Range("A29:A42").Find(What:=SearchString, LookIn:=xlValues, LookAt _
:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
If ra Is Nothing Then
MsgBox "String not available"
Else
Range("D" & k).Value = ra.Offset(0, 1).Address 'Change "D1" to whereever you want to put your result in
End If
k = k + 1
Next cell
End Sub
The code would check for every vendor (in my code range "E1:E10"), where is the cell in your range A29:A42 and returns the address of the cell next to it.
Some people prefer to find all occurrences of a searched item, and then change the value or the formula, or do else. Here is some code allowing great flexibility using an array.
'**************************************************************************************************************************************************************
'To return an array of information (value, formula, address, row, and column) for all the cells from a specified Range that have the searched item as value
'Returns an empty array if there is an error or no data
'**************************************************************************************************************************************************************
Public Function makeArrayFoundCellInfoInRange(ByVal itemSearched As Variant, ByVal aRange As Variant) As Variant
Dim cell As Range, tmpArr As Variant, x As Long
tmpArr = Array()
If TypeName(aRange) = "Range" Then
x = 0
For Each cell In aRange
If itemSearched = cell.Value Then
If x = 0 Then
ReDim tmpArr(0 To 0, 0 To 4)
Else
tmpArr = reDimPreserve(tmpArr, UBound(tmpArr, 1) + 1, UBound(tmpArr, 2))
End If
tmpArr(x, 0) = cell.Value
tmpArr(x, 1) = cell.Formula
tmpArr(x, 2) = cell.Address(0, 0) 'Without the dollar signs
tmpArr(x, 3) = cell.Row
tmpArr(x, 4) = cell.Column
x = x + 1
End If
Next cell
End If
makeArrayFoundCellInfoInRange = tmpArr
Erase tmpArr
End Function

Need to find an occurrence of a value in any beyond worksheet one and return the value of A:1 for each worksheet

I need to search all worksheets for the values in Worksheet one column A. The behavior should be similar to a CTRL-F find all selection. In A:1 of every worksheet is a name and if the value from column A is in that worksheet then A:1 will be returned. I do not need VLookup or HLookup. It might be doable with index and search combo, but I am not finding a good way to do that. I know I need an array search of some sort since I need to search everywhere. I have a solution that does not scale and is sloppy on the return. This is the formula I am currently using.
Column A is where the search values are pasted. Columns B-Z or however far is needed get the formula pasted in the first 200 rows which is the limit of the allowed search terms.
{=IF(OR($A2<>""),IF(OR($A2=Sheet26!$A$1:SZ$25000),Sheet26!A$1,"Not Found"),"")}
That is the formula for column Z and the sheet numbers are changed for each column that has a sheet. What I need to adjust this to is only having the formula in column B and it returning a concatenated value of all the names it found. There are lots of questions dealing with just one value or one range like this EXCEL: Need to find a value in a range of cells from another worksheet and return value from adjacent cell but nothing that actually answers what I need.
Currently the result I get is something like this.
A B C D E ...
Star Bob Not Found Ann Not Found
Light Bob Jill Not Found Not Found
378 Not Found Jill Not Found Not Found
What I would like to have is this
A B
Star Bob, Ann
Light Bob, Jill
378 Jill
How can I modify my formula to accomplish that?
Thanks
If you get tired of the formula approach, here is a VBA approach that should do what you describe.
It looks at column 1 on sheet1 to get a list of words to search for
read that list into a vba array (for speed)
for each item in the list, search each worksheet to see if the item exists
I added each item to a Dictionary, and then concatenated the results with commas, but you could also construct a string on the fly, to store in the second "column" of the array
After all is done, we write the results back to the worksheet.
It should be able to handle any reasonable number of worksheets and search terms
If necessary, you can limit the range to search on each worksheet; exclude certain worksheets from being searched; look at partial matches in a cell; select a case-sensitive search; etc.
If there are blank entries between the first and last search terms, I have excluded the search.
Option Explicit
Sub FindAllColA()
Dim WB As Workbook, WS As Worksheet
Dim WS1 As Worksheet
Dim D As Object
Dim V
Dim R As Range
Dim FirstRow As Long, LastRow As Long
Dim I As Long
Set D = CreateObject("scripting.dictionary")
Set WB = ThisWorkbook
Set WS1 = WB.Worksheets("Sheet1")
With WS1
If .Cells(1, 1) <> "" Then
FirstRow = 1
Else
FirstRow = .Cells(1, 1).End(xlDown).Row
End If
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
'V will hold both search terms and the results
V = .Range(.Cells(FirstRow, 1), .Cells(LastRow, 1)).Resize(columnsize:=2)
End With
For I = 1 To UBound(V)
If Not V(I, 1) = "" Then
D.RemoveAll
For Each WS In WB.Worksheets
If Not WS.Name = WS1.Name Then
With WS
If Not .Cells.Find(what:=V(I, 1), LookIn:=xlValues, _
lookat:=xlWhole, MatchCase:=False) Is Nothing Then
D.Add .Cells(1, 1).Text, .Cells(1, 1).Text
End If
End With
End If
Next WS
V(I, 2) = Join(D.Keys, ",")
Else
V(I, 2) = ""
End If
Next I
With WS1
Set R = .Range(.Cells(FirstRow, 1), .Cells(LastRow, 2))
R.EntireColumn.Clear
R = V
R.EntireColumn.AutoFit
End With
End Sub
Another way, would be an UDF which can be used in a wider range without any changes like:
Public Function ValString(search_term As String, cell_string As Variant, ParamArray ignored_sheets()) As Variant
Dim x As Variant
If TypeOf cell_string Is Range Then cell_string = cell_string.Address
If Not TypeOf Evaluate(cell_string) Is Range Then
ValString = CVErr(2023)
Exit Function
ElseIf Range(cell_string).Cells.Count > 1 Then
ValString = CVErr(2023)
Exit Function
End If
If IsMissing(ignored_sheets) Then
ignored_sheets = Array(Application.Caller.Parent.Name)
Else
For x = 0 To UBound(ignored_sheets)
If TypeOf ignored_sheets(x) Is Range Then
ignored_sheets(x) = ignored_sheets(x).Parent.Name
ElseIf TypeName(ignored_sheets(x)) = "String" Or IsNumeric(ignored_sheets(x)) Then
ignored_sheets(x) = Format(ignored_sheets(x), "#")
Else
ignored_sheets(x) = ""
End If
Next
End If
For Each x In ThisWorkbook.Worksheets
If IsError(Application.Match(x.Name, Array(ignored_sheets)(0), 0)) Then
If Not x.Cells.Find(search_term, , -4163, 1, , , True) Is Nothing Then
ValString = ValString & ", " & x.Range(cell_string).Value2
End If
End If
Next
If Len(ValString) Then
ValString = Mid(ValString, 3)
Else
ValString = CVErr(2042)
End If
End Function
Put the code in a Module and you can use it like a normal formula in your sheet.
Example:
=ValString(A1,"A1")
Or for your case:
=IFERROR(ValString(A1,"A1"),"Not Found")
Use: ValString([search_term],[cell_string],{[ignored_sheet1],[ignored_sheet2],...})
[search_term]: the string to look for
[cell_string]: the address of a cell as ref or string which you want to output if found
[ignored_sheets]: (optional) the sheet names as strings or a ref to them you want to ignore
If [ignored_sheets] is omitted the sheet you have the formula in will be ignored. To include all sheets in the workbook simply set it to ""
If nothing was found it will return #N/A! (which is good as you can catch this to set whatever output you want without changing the code)
If [cell_string] is not an address-string and/or goes for multiple cells, it will return #REF!
[ignored_sheets] is used as a list like =ValString(A1,"A1",Sheet1!A1,Sheet5!A1) or =ValString(A1,"A1","Sheet3","Sheet4","Sheet7","MyWhateverSheetName"). If used in the ref-way, you can rename the sheets and it will also in the formula. This is good if there is a summary sheet you do not want to check. But keep in mind: if used, the sheet with the formula itself, also needs to be included!
If you still have any questions, just ask ;)
try this UDF
Function findKeywords(findMe As String) As String
findKeywords = ""
Dim sheetToSkip As String
sheetToSkip = "Sheet1"
Dim sht As Worksheet
For Each sht In ActiveWorkbook.Sheets
If sht.Name <> sheetToSkip And Len(findMe) > 0 Then ' do not look for blank cells
' note: LookAt:=xlWhole ... whole word LookAt:=xlPart ... partial
Dim aaa As Range
Set aaa = sht.Cells.Find( _
What:=findMe, _
After:=sht.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
If Not aaa Is Nothing Then
If Len(findKeywords) = 0 Then
findKeywords = sht.Range("a1")
Else
findKeywords = findKeywords & ", " & sht.Range("a1")
End If
End If
End If
Next sht
' If Len(findKeywords) = 0 Then findKeywords = "Not Found" ' uncomment to return "Not Found" if desired
' Debug.Print findKeywords
End Function

VBA: adding up irregular ranges

I need some help to create a macro which adds all the values on the column E between the rows with the "avg" word. the result should be displayed on the cells where the "Sum here" label is displayed. Both texts "avg" and "sum here" is just for illustrate the example, "avg" could be replaced by any other word and "sum here" should actually be the aggregation of the values above it.
The real challenge is that the number of ranges on column E is variable, so i would like to find a macro which is able to deal with "n" number of ranges on column E.
Finally, the values on column D are only the example of the expected value on the "sum here" cells.
This is what I have tried to far:
Sub Macro1()
'
' Macro1 Macro
'
Dim sumhere As Range
Dim startingpoint As Range
Dim endingpoint As Range
'
Range("C17").Select
Selection.End(xlDown).Select
If ActiveCell = "avg" Then
ActiveCell.Offset(rowoffset:=0, columnoffset:=2).Select
Set sumhere = ActiveCell
Set startingpoint = ActiveCell.Offset(rowoffset:=-1, columnoffset:=0)
Selection.End(xlUp).Select
If (ActiveCell.Value) = "Sum here" Then
Set endingpoint = ActiveCell.Offset(rowoffset:=1, columnoffset:=0)
sumhere.Formula = "=sum(range(startingpoint:endingpoint)"
Else
Selection.End(xlUp).Select
If (ActiveCell.Value) = "Sum here" Then
Set endingpoint = ActiveCell.Offset(rowoffset:=1, columnoffset:=0)
sumhere.Formula = "=Sum(Range(startingpoint.adress:endingpoint.adress))"
Else: End If
End If
End If
End Sub
Additionally, as you can see, I do not know, how to define a range using variables. My original idea was to combine this code with some kind of "do while" or/and "for i= 1 to x" and "next i". But I can't see how to combine it.
Using formula only, and providing that column A only has avg (or any text) on each subtotal row.
I've given two versions of the formula - the volatile version (updates everytime you change anything on the spreadsheet), and the non-volatile version (only updates if it needs to).
The formula should be entered on row 6 - change the $E6 to which ever row you need.
(volatile)
=SUM(OFFSET($E6,IFERROR(LOOKUP(2,1/($A$1:INDEX($A:$A,ROW()-1)<>""),ROW($A$1:INDEX($A:$A,ROW()-1))),0)-ROW()+1,,ROW()-1-IFERROR(LOOKUP(2,1/($A$1:INDEX($A:$A,ROW()-1)<>""),ROW($A$1:INDEX($A:$A,ROW()-1))),0)))
(non volatile):
=SUM(INDEX($E:$E,IFERROR(LOOKUP(2,1/($A$1:INDEX($A:$A,ROW()-1)<>""),ROW($A$1:INDEX($A:$A,ROW()-1))),0)+1):INDEX($E:$E,ROW()-1))
or if you don't mind using a helper column:
In cell B6:
=IFERROR(LOOKUP(2,1/($A$1:INDEX($A:$A,ROW()-1)<>""),ROW($A$1:INDEX($A:$A,ROW()-1))),0)
In E6: (volatile)
=SUM(OFFSET($E6,$B6-ROW()+1,,ROW()-1-$B6))
or (non volatile):
=SUM(INDEX($E:$E,$B6):INDEX($E:$E,ROW()-1))
Edit:
Thought I'd add a UDF to calculate it to if you're after VBA.
Use the function =AddSubTotal() in the rows you want the sub total to be shown in, or use =AddSubTotal("pop",6) to sum everything in column F (col 6) using "pop" rather than "avg".
Public Function AddSubTotal(Optional Delim As String = "avg", Optional ColNumber = 5) As Double
Dim rCaller As Range
Dim rPrevious As Range
Dim rSumRange As Range
Set rCaller = Application.Caller
With rCaller.Parent
Set rPrevious = .Range(.Cells(1, 1), .Cells(rCaller.Row - 1, 1)).Find(Delim, , , , , xlPrevious)
If Not rPrevious Is Nothing Then
Set rSumRange = rPrevious.Offset(1, ColNumber - 1).Resize(rCaller.Row - rPrevious.Row - 1)
Else
Set rSumRange = .Range(.Cells(1, ColNumber), .Cells(rCaller.Row - 1, ColNumber))
End If
End With
AddSubTotal = WorksheetFunction.Sum(rSumRange)
End Function
The following VBA routine assumes that
your data is in Columns C:E
Nothing else relevant (nothing numeric) in that range
Your "key word" where you want to show the sum is avg
avg (the key word) is hard-coded in the macro
You could easily modify this routine to also perform an average of those values, and put those results, for example, in Column D
Any of the above are easily modified
Option Explicit
Sub TotalSubRanges()
Dim vSrc As Variant, rSrc As Range
Dim dAdd As Double
Dim I As Long
Const sKey As String = "avg"
Set rSrc = Range(Cells(1, "C"), Cells(Rows.Count, "C").End(xlUp)).Resize(columnsize:=3)
vSrc = rSrc
'Do the "work" in a VBA array, as this will
' execute much faster than working directly
' on the worksheet
For I = 1 To UBound(vSrc, 1)
If vSrc(I, 1) = sKey Then
vSrc(I, 3) = dAdd
dAdd = 0
Else
If IsNumeric(vSrc(I, 3)) Then dAdd = dAdd + vSrc(I, 3)
End If
Next I
'write the results back to the worksheet
' and conditionally format the "sum" cells
With rSrc
.EntireColumn.Clear
.Value = vSrc
.Columns(3).AutoFit
.EntireColumn.ColumnWidth = .Columns(3).ColumnWidth
.FormatConditions.Delete
.FormatConditions.Add _
Type:=xlExpression, _
Formula1:="=" & .Item(1, 1).Address(False, True) & "=""" & sKey & """"
With .FormatConditions(1)
.Interior.ColorIndex = 6
End With
End With
End Sub
Surely you just need something like:
Sub sums()
Dim i As Integer, j As Integer, k As Integer
j = Range("C1048576").End(xlUp).Row
k = 1
For i = 1 To j
If Range("C" & i).Value <> "" Then
Range("E" & i).Value = "=Sum(E" & k & ":E" & i - 1 & ")"
k = i + 1
End If
Next i
End Sub
Change:
Dim startingpoint As Range
Dim endingpoint As Range
To:
Dim startingpoint As Variant
Dim endingpoint As Variant
As the startingpoint and endingpoint is used in a formula, you cant define them as a Range.

Excel VBA: Application defined or Object defined error

I've written some code to look for sets of brackets in an excel file and white out the contents of the cells in between them. The code I have works for 26-27 lines before I get the error message.
Here is the code:
Sub macro()
Dim white As Long
Dim rowIndex As Long
Dim colIndex As Long
Dim lastRow As Long
Dim lastCol As Long
white = RGB(Red:=255, Green:=255, Blue:=255)
With ActiveSheet
lastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lastCol = .Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
For rowIndex = 1 To lastRow
For colIndex = 1 To lastCol
If .Cells(rowIndex, colIndex).Text = "[" Then
colIndex = colIndex + 1
Do While .Cells(rowIndex, colIndex).Value <> "]"
.Cells(rowIndex, colIndex).Font.Color = white
colIndex = colIndex + 1
Loop
End If
Next colIndex
Next rowIndex
End With
End Sub
The error occurs on this line:
Do While Cells(rowIndex, colIndex).Value <> "]"
I tried adding in:
With ActiveSheet
Along with . before each Cell command but it did not make a difference.
Any help is greatly appreciated.
If one of the cells containing [ or ] may have rogue leading trailing spaces/non-breaking spaces then a wildcard comparison should be made. Additionally, the worksheet's MATCH function can locate the bracketing cells with a wildcard search more efficiently than looping through each cell row-by-row.
Sub hide_cell_values()
Dim whiteOut As String '<~~ using alternate method .NumberFormat ;;;
Dim rw As Long, n As Long, f As Long, l As Long
whiteOut = ";;;" 'custom cell number format to show nothing in cell
With ActiveSheet
'process row by row in the .UsedRange
With .Range(.Cells(1, 1), .Cells.SpecialCells(xlCellTypeLastCell))
For rw = 1 To .Rows.Count
' check for existance of matching pairs
If Not IsError(Application.Match("*[*", .Rows(rw), 0)) And _
Application.CountIf(.Rows(rw), "*[*") = _
Application.CountIf(.Rows(rw), "*]*") Then
' [ and ] pairs exist and match in row.
f = 0: l = 0
For n = 1 To Application.CountIf(.Rows(rw), "*[*")
'this looks complicated but it just references the cells between [ & ]
f = Application.Match("*[*", .Rows(rw).Cells.Offset(0, l), 0) + l + 1
' last safety check to ensure that [ comes before ]
If Not IsError(Application.Match("*]*", .Rows(rw).Cells.Offset(0, f), 0)) Then
l = Application.Match("*]*", .Rows(rw).Cells.Offset(0, f), 0) + f - 1
With .Range(.Cells(rw, f), .Cells(rw, l))
'this is a better method of not displaying text in a cell
.NumberFormat = whiteOut '<~~ e.g. ;;;
'the old method of white-text-on-white-background (not reliable as .Interior.Color can change)
'.Font.Color = vbWhite
End With
End If
Next n
Else
' [ and ] pairs do not match or do not exist in row. do nothing.
End If
Next rw
End With
End With
End Sub
I have opted for a custom cell number format of ;;; rather than altering the font color to RGB(255, 255, 255) (see footnote ¹). A Range.NumberFormat property of three semi-colons in a row simply shows nothing; a white font's apparent visibility is subject to the cell's Range.Interior.Color property, the worksheet backgroun or even the 'Window background' in the computer's system settings.
        Before running sub
        After running sub
In the before and after images above, you can see that D2 retains its Range.Value property (visible in the formula bar) while showig nothing on the worksheet. Note: cell values can still be copied from a cell displaying nothing but that is a caveat of using the vbWhite method as well.
¹ There are predefined RGB long type constants for the basic VBA pallette. RGB(255, 255, 255) is equal to vbWhite. Full list available at Color Constants.

ignore alphabets while looping through cells

From my GUI , I enter numbers like this: 9811,7841 which will be sent to my macro. My macro is:
sub highlight(fm as variant)
dim sh as worksheet
Dim i As Integer
dim j as integer
dim k As Long
Dim rn As Range
din number() as integer
If phm <> 0 Then
phm = Split(phm, ",")
ReDim number(LBound(phm) To UBound(phm)) As Integer
Set sh = w.Worksheets("Sheet1")
sh.Select
Cells.Find("Type").Select
ActiveCell.Offset(1, 0).Select
Set rn = sh.UsedRange
k = rn.Rows.Count + rn.Row - 1
For i = 1 To k
For j = LBound(number) To UBound(number)
number(j) = CInt(phm(j))
If ActiveCell.Value = number(j) Or IsEmpty(ActiveCell.Value) Then
Selection.Interior.ColorIndex = xlNone
Else
Selection.Interior.Color = vbGreen
Exit For
End If
Next j
ActiveCell.Offset(1, 0).Select 'moves activecell down one row.
Next i
End If
ActiveWorkbook.Save
End Sub
I would like to modify my code in such that alphabets are ignored if present in any cell.In the below case, cell3 and cell 5 should be highlighted as my "fm" contains 9811,7841 so cell 1,2,4 are valid.Alphabets should be ignored if any while checking the cells.
Sheet1
cell 1: 9811
cell 2: hello 9811
cell 3: 3428
cell 4: hello 7841
cell 5:hello 2545
The simplest way to do this is with a regular expression. Add a reference to Microsoft VBScript Regular Expressions, then just do a pattern replacement:
Private Function StripNonNumerics(inValue As String) As String
Dim regex As New RegExp
With regex
.Pattern = "\D"
.Global = True
StripNonNumerics = .Replace(inValue, vbNullString)
End With
End Function
Note that there'll be less overhead if you incorporate this into your sub or make the regex a global (that way you don't have to repeatedly create the RegExp object.
I think you are looking for the VBA function "Instr"
https://msdn.microsoft.com/en-us/en-en/library/8460tsh1%28v=vs.90%29.aspx
Assuming that phm is your array that contains one number of fm in every cell:
you need to change your line
If ActiveCell.Value = number(j) Or IsEmpty(ActiveCell.Value) Then
to
If Instr(ActiveCell.Value,number(j)) > 0 Or IsEmpty(ActiveCell.Value) Then