When debugging or Quality Checking an Excel report at work I have found that the problem was because of text being hard coded inside a formula. I have heard this as being a Constant and Formula mixed cell.
Here are examples of what I see.
Constant =100
Constant =Facility
Formula cell =INDIRECT(ADDRESS(5,MATCH($A7&$B7&C$2,Data!$4:$4,0),,,$A$2))
Mixed cell =INDIRECT("Data!"&ADDRESS(5,MATCH($A7&$B7&C$2,Data!$4:$4,0)))
"Data!" is the Constant in the mixed cell, in this case the sheet name. If that sheet name ever changed, the formula would break. I have found and am using two conditional formats to highlight cells that are Constants and those that are formulas using this "Identify formulas using Conditional Formatting". I need to come up with a way to format those cells which contain these Constants inside of formulas.
I have found this question and tried using =IF(COUNT(SEARCH(CHAR(34),A1,1)),TRUE,FALSE) and FIND() to see if I could check if a cell had double quotes inside of it, but the SEARCH() returns FALSE since it is looking at the cells value and not it's contents. It returns TRUE if the cell contains "Constant" but if it is a formula it returns FALSE, such as if the cell contains ="Constant".
How can I find Constants inside formulas across a whole worksheet or workbook?
EDIT*
Thanks to Sidd's code below I have made a function in a module I can use in conditional formatting to at least highlight cells that contain quotes inside the cells.
Function FormulaHasQuotes(aCell)
If InStr(1, aCell.Formula, """") Then
FormulaHasQuotes = True
Else
FormulaHasQuotes = False
End If
End Function
Let's say your sheet looks like this.
Is this what you are trying?
Sub Sample()
Dim ws As Worksheet
Dim aCell As Range, FRange As Range
'~~> Set this to the relevant sheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Find all the cells which have formula
On Error Resume Next
Set FRange = .Cells.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not FRange Is Nothing Then
'~~> Check for " in the cell's formula
For Each aCell In FRange
If InStr(1, aCell.Formula, """") Then
Debug.Print "Cell " & aCell.Address; " has a constant"
End If
Next
End If
End With
End Sub
When you run the above code, you get this output
Cell $A$2 has a constant
Cell $A$5 has a constant
Note: I have shown you how to do it for a sheet, i am sure you can replicate it for all sheets in a workbook?
Only very lightly tested...
For example will not handle "string" constants which contain embedded "
Sub Tester()
'add reference to "Microsoft VBScript Regular Expressions 5.5"
Dim regxnum As New RegExp, regexpchar As New RegExp
Dim matches As MatchCollection, m As Match
Dim rngF As Range, c As Range
On Error Resume Next
Set rngF = ActiveSheet.UsedRange.SpecialCells(xlFormulas)
On Error GoTo 0
If Not rngF Is Nothing Then
regxnum.Pattern = "[^A-Z$](-?\d{1,}\.?\d{0,})"
regxnum.Global = True
regexpchar.Pattern = "(""[^""]{0,}"")"
regexpchar.Global = True
For Each c In rngF.Cells
Debug.Print c.Formula
Set matches = regxnum.Execute(c.Formula)
For Each m In matches
Debug.Print c.Parent.Name, c.Address(), m.SubMatches(0)
Next m
Set matches = regexpchar.Execute(c.Formula)
For Each m In matches
Debug.Print c.Parent.Name, c.Address(), m.SubMatches(0)
Next m
Next c
End If
End Sub
Related
I cannot seem to find what i am looking for so here i am.
The situation: We have a spreadsheet that is used by multiple users. They will have to fill in certain cells with an employee's name, but they must be typed exactly as in our system. To remove as much human error as possible, we are making a simple button they can push after typing in their last name and a Vlookup gives us the proper format.
Problem: There are about 10 cells all in one column (B10:B19) that are where the names will go. The vlookup output is in Cell G4. So we want if they press the button, the contents of G4 goes in the next available cell within that range of B10-B19. I have gotten close but it appears to skip some lines and miss others.
Here is what i have so far:
Sub SecondTestFunction()
Dim cellRange As Range
Dim nameInCell As Range
Set cellRange = Range("B11:B20")
'Loop through cells in range B11 thru B20
For i = 1 To cellRange.Count
'Set nameInCell to equal the index of column B
Set nameInCell = cellRange(i)
'If the cell in Column B is empty....
If IsEmpty(nameInCell) Then
'Paste the name from cell G4...
nameInCell(i).Value = Range("G4")
GoTo GoToHere
Else
MsgBox "Cell is NOT EMPTY"
nameInCell(i).Interior.ColorIndex = 3 'Testing line to see which get affected
End If
Next i
GoToHere:
MsgBox "Done looping"
End Sub
Any help is appreciated!
You can do something like this:
Sub SecondTest()
Dim c As Range, bFound As Boolean, ws As Worksheet
Set ws = ActiveSheet 'always use an explicit sheet
For Each c in ws.Range("B11:B20").Cells
If Len(c.value) = 0 Then
c.Value = ws.Range("G4").Value
bFound = True
Exit for
End If
Next c
If not bFound Then Msgbox "No empty cell found!"
End Sub
Is it possible to write a vba macro that determines if there are any empty cells in a given range and returns the row number of that cell?
I'm new to vba and all that I managed to write after searching the internet was something that takes a range and colors every emty cell in it red:
Sub EmptyRed()
If TypeName(Selection) <> "Range" Then Exit Sub
For Each cell In Selection
If IsEmpty(cell.Value) Then cell.Interior.Color = RGB(255, 0, 0)
Next cell
End Sub
The macro does basically what I want, but instead of coloring the empty cell red I would like to know the row index of the empty cell.
A little background info: I have a very large file (about 80 000 rows) that contains many merged cells. I want to import it into R with readxl. Readxl splits merged cells, puts the value in the first split cell and NA into all others. But a completely empty cell would also be assigned NA, so I thought the best thing would be to find out which cells are empty with Excel, so that I know which NA indicate a merged cell or an empty cell. Any suggestions on how to solve this problem are very welcome, thanks!
Edit: To clarify: Ideally, I want to unmerge all cells in my document and fill each split cell with the content of the previously merged cell. But I found macros on the web that are supposed to do exactly that, but they didn't work on my file, so I thought I could just determine blank cells and then work on them in R. I usually don't work with Excel so I know very little about it, so sorry if my thought process is far too complicated.
To do exactly what you state in your title:
If IsEmpty(cell.Value) Then Debug.Print cell.Row
But there are also Excel methods to determine merged cells and act on them. So And I'm not sure exactly what you want to do with the information.
EDIT
Adding on what you say you want to do with the results, perhaps this VBA code might help:
Option Explicit
Sub EmptyRed()
Dim myMergedRange As Range, myCell As Range, myMergedCell As Range
Dim rngProcess As Range
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
Set rngProcess = Range("A1:B10")
For Each myCell In rngProcess
If myCell.MergeCells = True Then
Set myMergedRange = myCell.MergeArea
With myMergedRange
.MergeCells = False
.Value = myCell(1, 1)
End With
End If
Next myCell
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With
End sub
Note that I explicitly declare all variables, and I hard coded the range to check. There are various ways of declaring the range to be checked; using 'Selection' is usually rarely preferred.
Before anything else: From the opposite end of the spectrum, you can use Range.MergeCells or Range.MergeArea to determine if a Cell is part of a Merged Area. But, I digress...
You can use Cell.Row to get the row number. How you return or display that is up to you - could be a Message Box, a delimited string, or an array, or even a multi-area range.
A Sub cannot return anything once called, so you may want a Function instead, e.g. Public Function EmptyRed() As String
(Also, I would recommend you get in the habit of explicitly declaring all of your variables, and perhaps using Option Explicit too, before you run into a typo-based error. Just add Dim cell As Range at the top of the sub for now)
Sub FF()
Dim r, wksOutput As Worksheet
Dim cell As Range, rng As Range, rngArea As Range
With Selection
.UnMerge
'// Get only blank cells
Set rng = .SpecialCells(xlCellTypeBlanks)
'// Make blank cells red
rng.Interior.Color = vbRed
End With
'// Create output worksheet
Set wksOutput = Sheets.Add()
With wksOutput
For Each rngArea In rng.Areas
For Each cell In rngArea
r = r + 1
'// Write down the row of blank cell
.Cells(r, 1) = cell.Row
Next
Next
'// Remove duplicates
.Range("A:A").RemoveDuplicates Array(1), xlNo
End With
End Sub
There are a couple ways:
Sub EmptyRed()
Dim rgn,targetrgn as range
Dim ads as string ‘ return rgn address
Set targetrgn= ‘ your selection
For Each rgn In Targetrgn
If IsEmpty(rgn.Value) Then
‘1. Use address function, and from there you can stripe out the column and row
Ads=application.worksheetfunction.addres(cell,1)’ the second input control the address format, w/o $
‘2. Range.row & range.column
Ads=“row:” & rgn.row & “, col: “ & rgn.column
End if
Next rgn
End Sub
Ps: I edited the code on my phone and will debug further when I have a computer. And I am just more used to use “range” rather than “cell”.
To clarify: Ideally, I want to unmerge all cells in my document and fill each split cell with the content of the previously merged cell.
Cycle through all cells in the worksheet's UsedRange
If merged, unmerge and fill the unmerged area with the value from the formerly merged area.
If not merged but blank, collect for address output.
Sub fillMerged()
Dim r As Range, br As Range, mr As Range
For Each r In ActiveSheet.UsedRange
If r.Address <> r.MergeArea.Address Then
'merged cells - unmerge and set value to all
Set mr = r.MergeArea
r.UnMerge
mr.Value = mr.Cells(1).Value
ElseIf IsEmpty(r) Then
'unmerged blank cell
If br Is Nothing Then
Set br = r
Else
Set br = Union(br, r)
End If
End If
Next r
Debug.Print "blank cells: " & br.Address(0, 0)
End Sub
I am trying to produce a VBA function that will hide all columns for which cells D9:CC9 are not equal to "A6" and cells D8:CC8 are not equal to "12." Based on the script below, the system keeps returning an error. I am new to VBA, was hoping someone might be able to assist.
Thanks!
Dim MyCell As Range
Set MyCell = Range("D9:CC9,D8:CC8")
For Each cell In MyCell
If cell.Value <> WorksheetFunction.Index(Range("D9:CC9"),WorksheetFunction.Match(Range("A6")&"12",Range("D9:CC9")&Range("D8:CC8"), 0))
cell.EntireColumn.Hidden = True
End If
Next cell
Most operations are performed quite different using VBA than doing them manually. If you want to work with VBA then should do some research about working with variables and objects. This pages should be of interest.
Variables & Constants, Excel Objects, With Statement & Range Properties (Excel)
I have done some changes to your code, see comments within, and refer to the pages mentioned above.
Sub Rng_HideColumns()
Dim rTrg As Range, rCol As Range
Dim sCllVal As String
Rem Set rTrg = ThisWorkbook.Sheets("Sht(0)").Range("D9:CC9,D8:CC8")
Rem Refers to the worksheet you want to work with instead or using the active worksheet
With ThisWorkbook.Sheets("Sht(0)")
Rem Get value to match
sCllVal = .Range("A6").Value2 & 12
Rem Set Range to Search
Set rTrg = .Range("D8:CC9")
For Each rCol In rTrg.Columns
With rCol
If .Cells(2).Value2 & .Cells(1).Value2 = sCllVal Then
.EntireColumn.Hidden = 1
Else
.EntireColumn.Hidden = 0
End If: End With: Next: End With
End Sub
Im a beginner with Excel VBA
my question is if I have string in a cell like "MyNameIsHammadAndImFromIreland".
All cells have strings/sentences but there is no spaces.
How can I find if the cell includes the word "Ireland"?
The following VBA code will iterate through the used cells in a given worksheet and find any that match the given criteria. At the end, a message box is displayed showing a list of cells that contain the search term.
This functionality is equivalent to using the 'Find All' option you can choose when you use the normal find functionality available by pressing CTRL + F.
Option Explicit
Private Sub Find()
Dim rngResult As Range
Dim strToFind As String
'Set to your desired string to find
strToFind = "Ireland"
'If the string you are searching for is located in
'the worksheet somewhere, you can set the value
'like this: strToFind = Worksheets("Sheet1").Range("A1").Value
'This assumes your search term is in cell A1 of the
'Sheet1 worksheet.
'Look in the used range of a given worksheet
'Change Sheet1 to match your worksheet name
With Worksheets("Sheet1").UsedRange
'Find the first cell that contains the search term
Set rngResult = .Find(What:=strToFind, LookAt:=xlPart)
'If it is found, grab the cell address of where the
'search term can be found
If Not rngResult Is Nothing Then
Dim firstAddress As String, result As String
firstAddress = rngResult.Address
'Loop through the rest of the cells until returning
'to the first cell that we had a match in.
Do
'Record the cell address of the match
'to the result string
result = result & rngResult.Address & ","
'Go to next cell containing the search term
Set rngResult = .FindNext(rngResult)
'Exit the loop when we reach the starting point
Loop While rngResult.Address <> firstAddress
'Output the list of cells that contain the string to find
MsgBox "Found """ & strToFind & """ in cell(s): " & result
End If
End With
End Sub
Be sure to set strToFind to your desired string, and change Sheet1 to match the name of whichever sheet you want to search over.
You don't need VBA, just use a formula:
=IF(LEN(SUBSTITUTE(A1,"Ireland",""))<LEN(A1),"Word Found","Word NOT found")
If you really want VBA then:
hasWord = InStr(Range("A1").Value, "Ireland") > 0 '// returns TRUE or FALSE
I have two worksheets, I want to use a value in sheet to_approve to lookup against column A in sheet submitted, then identify the cell reference so I can paste a value in the cell adjacent (column B).
I have used the following to identify the cell reference, but I don't know how to use it in VBA code.
=ADDRESS(MATCH(To_Approve!D19,Submitted!A:A,0),1,4,1,"submitted")
While many functions can be used in VBA using Application.WorksheetFunction.FunctionName ADDRESS is not one of these (MATCH is)
But even it it was available I would still use a Find method as below as it:
gives you the ability to match whole or part strings, case sensitive or not
returns a range object to work with if the value is found
readily handles a no match
you can control the point in the range being search as to where the search starts
multiple matches can be returned with FindNext
something like
Sub GetCell()
Dim ws As Worksheet
Dim rng1 As Range
Set ws = Sheets("submitted")
Set rng1 = ws.Columns("A").Find(Sheets("To_Approve").[d19], , xlValues, xlWhole)
If Not rng1 Is Nothing Then
MsgBox rng1.Address & " in sheet " & ws.Name
Else
MsgBox "not found", vbCritical
End If
End Sub
This example should give you an idea of how to find a corresponding value on another sheet and place a second value in the the column to the left. When using VBA, it is not necessary to select cells and then paste; you can directly enter a value into a range (cell) object.
Sub TransferValue()
Dim rngSearch As Range
Dim rngFind As Range
Dim dValue As Double
' initialization
Set rngSearch = Worksheets("to_approve").Range("D19")
dValue = Date
' find the match & insert value
Set rngFind = Worksheets("submitted").Columns(1).Find(What:=rngSearch.Value)
If Not rngFind Is Nothing Then
rngFind.Offset(ColumnOffset:=1).Value = dValue
End If
End Sub
(Note: dValue is a placeholder for whatever value you want to enter.)