Using wildcards in VBA cells.replace - excel

I'm looking to write a function in Excel to add leading zeroes to the octets that make up an IP address: e.g in 172.19.1.17 I want to to change .19. to .019., the .1. to .001., and the .17 at the end to .017.
Te Cells.Teplace function does not seem to accept ? as a wildcard. Also, is there a way I can represent 'end of string' so I'll be able to add leading zeroes to the last octet, .17 in the example above.
Thanks Ian
Cells.Replace What:=".1?.", Replacement:=".01?.", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
This does find "10." "11." "12." etc. but replaces them all with ".01?."

As an alternative you may use this formula to add zeros to IP parts (it looks terrible, but treats separately all the parts and finally mix them up):
=REPT(0,4-FIND(".",A1))&LEFT(A1,FIND(".",A1)-1)&"."&
REPT(0,4-FIND("#",SUBSTITUTE(A1,".","#",2))+FIND(".",A1))&MID(A1,FIND(".",A1)+1,FIND("#",SUBSTITUTE(A1,".","#",2))-FIND(".",A1)-1)&"."&
REPT(0,4-FIND("#",SUBSTITUTE(A1,".","#",3))+FIND("#",SUBSTITUTE(A1,".","#",2)))&MID(A1,FIND("#",SUBSTITUTE(A1,".","#",2))+1,FIND("#",SUBSTITUTE(A1,".","#",3))-FIND("#",SUBSTITUTE(A1,".","#",2))-1)&"."&
REPT(0,3-LEN(A1)+FIND("#",SUBSTITUTE(A1,".","#",3)))&RIGHT(A1,LEN(A1)-FIND("#",SUBSTITUTE(A1,".","#",3)))
You may paste it as it is to B1 (assuming your IPs are in column A starting A1) regardless line breaks.
Sample file: https://www.dropbox.com/s/vun6urvukch9uvv/IPoctets.xlsx

You could do something like this:
Be sure to replace Application.UsedRange with the actual range containing the IP addresses
Sub PadIP()
Dim Arr As Variant
Dim ipAddr As String
Dim vCell As Variant
Dim n As Long
'Replace ActiveSheet.UsedRange with the range containing your data
'
'If data is contained in column A and you have a column header
'Example: Range(Cells(2, 1), Cells(ActiveSheet.UsedRange.Rows.Count, 1))
For Each vCell In ActiveSheet.UsedRange
Arr = Split(vCell.Value, ".")
For n = 0 To UBound(Arr)
If (n + 1) Mod 4 = 0 Then
ipAddr = ipAddr & Right(String(3, "0") & Arr(n), 3)
Else
ipAddr = ipAddr & Right(String(3, "0") & Arr(n), 3) & "."
End If
Next
vCell.Value = ipAddr
ipAddr = ""
Next
End Sub

Can I play too :)?
This is further to my comment above. This is an example on how to find .??. and make it .0??.
I am assuming that the data can be ANYWHERE in the worksheet.
Sub Sample()
Dim oRange As Range, aCell As Range, bCell As Range
Dim ws As Worksheet
Dim ExitLoop As Boolean
Dim SearchString As String
On Error GoTo Whoa
Set ws = Worksheets("Sheet1")
Set oRange = ws.Cells
SearchString = ".??."
Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
aCell.Value = CleanIt(aCell.Value)
Do While ExitLoop = False
Set aCell = oRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
aCell.Value = CleanIt(aCell.Value)
Else
ExitLoop = True
End If
Loop
End If
Exit Sub
Whoa:
MsgBox Err.Description
End Sub
Function CleanIt(rng)
Dim MyAr() As String
Dim strTemp As String
MyAr = Split(rng, ".")
For i = LBound(MyAr) To UBound(MyAr)
If Len(MyAr(i)) = 2 Then
MyAr(i) = "0" & MyAr(i)
End If
strTemp = strTemp & "." & MyAr(i)
Next i
CleanIt = Mid(strTemp, 2)
End Function
Screenshot
NOTE: This is just an example for demonstration purpose. The above code needs to be tweaked more so that it can handle other scenarios as well.

Related

Extracting two numbers from a cell then adding them together

I am trying to work on a VBA macro that would extract two numbers from a cell and then add them together. The spreadsheet I am working on has a field like this:
Cell D1: .60 #2021-71; 0.90 #2021-71
I need to take the .60 and .90 out, add them together, and place them back in the cell.
For reference, there are other cells in this column that are like this:
Cell D2: .70 #2021-71
I have code that is already looking through the column and removing everything from the # sign on:
Dim tmp As String
For Each cell In Range("D:M")
If InStr(cell.Value, "#") > 0 Then
tmp = cell.Value
cell.Value = Left(tmp, InStr(tmp, "#") - 1)
End If
Is what I am trying to do even possible?
I've taken the approach of providing a custom function which you can then refer to on sheet.
You can call the function whatever you want...!
Public Function SumFirstNumbers(ByVal rngCell As Range) As Variant
Dim arrValues, i As Long, strValue As String, dblValue As String
If InStr(1, rngCell.Text, "#") > 0 Then
arrValues = Split(rngCell.Text, ";")
For i = 0 To UBound(arrValues)
dblValue = 0
strValue = Split(Trim(arrValues(i)), " ")(0)
If IsNumeric(strValue) Then dblValue = CDbl(strValue)
SumFirstNumbers = CDbl(SumFirstNumbers) + dblValue
Next
Else
SumFirstNumbers = rngCell.Value
End If
End Function
Then just use it like any other function in a cell...
This way, you can fill down and across and not have to worry about where the source data actually resides.
To then put it back in the original cells, just Copy → Paste Special → Values.
If it produces an incorrect result (before copying back to the original cells), the function can be changed and the data is still protected.
Naturally, this could still be incorporated into a wider macro if need be. You just need to apply it to your original code.
Dim tmp As String
For Each cell In Range("D:M")
If InStr(cell.Value, "#") > 0 Then
tmp = cell.Value
cell.Value = SumFirstNumbers(cell)
End If
Next
... something like that anyway.
Non VBA Method
Using formulas only. I have indented the formula (you can do that in the formula bar) for a better understanding.
=IFERROR(
IF(
ISNUMBER(SEARCH(";",D1)),
VALUE(MID(D1,SEARCH(";",D1)+1,SEARCH("#",D1,SEARCH(";",D1)+1)-SEARCH(";",D1)-1)) + VALUE(LEFT(D1,SEARCH("#",D1)-1)),
VALUE(LEFT(D1,SEARCH("#",D1)-1))
),0
)
Logic:
Check if there is ; using SEARCH(). Use ISNUMBER() to handle the formula if it doesn't exist.
If there is ; then get the text between ; and # using MID(). Convert them to values using VALUE() and add them up.
If there is no ; then just use LEFT() to get the number before #.
VBA Method
In case you are looking for VBA method to replace the values in the same column then here is a faster method using WildCards. If you have lots of data then in the end where I am using For Each aCell In rng, put the data in an array and loop the array instead.
Logic:
Make Excel do most of the Dirty work!
Replace every thing that is between ";" and "#" with "" using inbuit .Replace with wildcard "#*;"
Replace every thing that is after "#" with "" using wildcard "#*"
Remove all spaces
Use Evaluate.
Code:
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim rng As Range, aCell As Range
Dim lRow As Long
Set ws = Sheet1
With ws
With .Columns(4)
.Replace What:="#*;", Replacement:="+", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False, FormulaVersion:=xlReplaceFormula2
.Replace What:="#*", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False, FormulaVersion:=xlReplaceFormula2
.Replace What:=" ", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False, FormulaVersion:=xlReplaceFormula2
End With
lRow = .Range("D" & .Rows.Count).End(xlUp).Row
Set rng = .Range("D1:D" & lRow)
For Each aCell In rng
aCell.Value = .Evaluate(aCell.Value)
Next aCell
End With
End Sub
In Action
Replace by Numbers
Option Explicit
Sub ReplaceByNumbers()
Const Cols As String = "D:M"
Const FindDelimiter As String = "#"
Const SplitDelimiter As String = ";"
Dim ws As Worksheet: Set ws = ActiveSheet ' improve
Dim rg As Range: Set rg = Intersect(ws.UsedRange, ws.Columns(Cols))
If rg Is Nothing Then Exit Sub ' no data
Dim rCount As Long: rCount = rg.Rows.Count
Dim cCount As Long: cCount = rg.Columns.Count
Dim Data As Variant
If rCount + cCount = 2 Then ' one cell only
ReDim Data(1 To 1, 1 To 1): Data(1, 1).Value = rg.Value
Else ' multiple cells
Data = rg.Value
End If
Dim SubStrings() As String
Dim r As Long, c As Long, n As Long
Dim iPos As Long
Dim Total As Double
Dim cString As String
Dim NumberFound As Boolean
For r = 1 To rCount
For c = 1 To cCount
cString = CStr(Data(r, c))
iPos = InStr(cString, FindDelimiter)
If iPos > 0 Then
SubStrings = Split(cString, SplitDelimiter)
For n = 0 To UBound(SubStrings)
If n > 0 Then
iPos = InStr(SubStrings(n), FindDelimiter)
End If
cString = Trim(Left(SubStrings(n), iPos - 1))
If Left(cString, 1) = "." Then cString = "0" & cValue
If IsNumeric(cString) Then
If NumberFound Then
Total = Total + CDbl(cString)
Else
Total = CDbl(cString)
NumberFound = True
End If
End If
Next n
If NumberFound Then
Data(r, c) = Total
NumberFound = False
End If
End If
Next c
Next r
rg.Value = Data
MsgBox "Replaced by numbers.", vbInformation, "ReplaceByNumbers"
End Sub

Highlight all words in a long text that is in a Cell

I am trying to develop a Find button, to mark in red "ALL" of the word that are contained in a cell.
For example If I have in my cell this text.
"Pepper had peppermint in his pocket"
it should change to this.
"Pepper had peppermint in his pocket"
This code highlights the first word that it finds.
Dim i As Long
Dim oldrngrow As Long
Dim myValue As String
Dim arr() As Variant
arr = Array(TextBox1.Value)
TextBox2.Text = UBound(arr)
For i = 1 To UBound(arr) + 1
myValue = arr(i - 1)
If myValue = vbNullString Then
MsgBox ("Please Enter a Word in Textbox")
End
End If
Set rng = Cells.Find(What:=myValue, After:=Cells(1, i), LookIn:= _
xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
xlNext, MatchCase:=False, MatchByte:=True, SearchFormat:=False)
If rng Is Nothing Then
GoTo skip
End If
oldrngrow = rng.Row
Do While rng.Column = i
If ComboBox1.Text = "Red" Then
rng.Characters(InStr(rng, myValue), Len(myValue)).Font.ColorIndex = 3
Set rng = Cells.FindNext(After:=rng)
If oldrngrow = rng.Row Then
Exit Do
End If
Loop
skip:
Next i
Interesting question. After some research, I’ve put together the following code to demonstrate how to highlight every instance of a word in a string within a cell. For the sake of the demonstration, it uses an Input Box to get the desired string-to-highlight (you can change the method), and assumes the range to search is simply A1 – again you can change this to whatever you want.
Make sure you include Option Compare Text at the top of the Sub – otherwise the search will be case sensitive. Let me know how you go.
Option Compare Text
Sub StringColor()
Dim myRange As Range, myCell As Range, myString As String, myCount As Integer
Set myRange = Range("A1")
myString = InputBox("Type the word you want to color in A1")
For Each myCell In myRange
For myCount = 1 To Len(myCell) - Len(myString) + 1
If Mid(myCell, myCount, Len(myString)) = myString Then
myCell.Characters(myCount, Len(myString)).Font.Color = vbRed
End If
Next myCount
Next myCell
End Sub

Replace method and changing format?

I'm using vba method Replace, and I need to change every "/" to ",". This looks like a simple task so I use:
ActiveWorkbook.Worksheets(2).Cells.Replace What:="_/_", Replacement:=",", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=True, _
ReplaceFormat:=True
The problem is when one of cells has value like:
04_/_2018
And the result is:
4,2018
instead of:
04,2018
All of my cells in this workbook has text formating before and after aplying the code. My guess is that Excel in a process is changing the format to general for a moment and it cut offs not necessary for a number left zero.
I've tried to bypass this issue by changing parameters of the method (none of this worked) and changing the decimal separator from "," to ".". This helped when using find and replace by hand from Excel, but when I record it and try to use as Macro it doesn't work. What can I do to prevent Excel from cutting off zeros in this scenarios?
If you want 04,2018 then use .Find/.FindNext then replace+reconstruct the value before placing in the cell.
Is this what you are trying?
Sub Sample()
Dim oRange As Range, aCell As Range, bCell As Range
Dim ws As Worksheet
Dim ExitLoop As Boolean
Dim SearchString As String
On Error GoTo Whoa
Set ws = Worksheets("Sheet1")
Set oRange = ws.UsedRange
SearchString = "_/_"
Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
If Left(aCell.Value, 1) = 0 Then
aCell.Value = "'" & Replace(aCell.Value, SearchString, ",")
Else
aCell.Value = Replace(aCell.Value, SearchString, ",")
End If
Do While ExitLoop = False
Set aCell = oRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
If Left(aCell.Value, 1) = 0 Then
aCell.Value = "'" & Replace(aCell.Value, SearchString, ",")
Else
aCell.Value = Replace(aCell.Value, SearchString, ",")
End If
Else
ExitLoop = True
End If
Loop
Else
MsgBox SearchString & " not Found"
End If
Exit Sub
Whoa:
MsgBox Err.Description
End Sub
Screenshot
The leading zeroes are automatically removed in Excel by default. Thus 04,2014 is changed to 4,2014. A way to work around this is to format the cells as Text, adding this line before the Replace():
ActiveWorkbook.Worksheets(2).Cells.NumberFormat = "#"
Formatting to Text has a lot of unpleasant changes, e.g. the text goes to the left and Excel does not recognize the dates/numbers by default.
This is a simple sample of the code, changing 1 cell:
Sub TestMe()
ActiveWorkbook.Worksheets(1).Cells.NumberFormat = "General"
Range("B5") = "05_2018"
ActiveWorkbook.Worksheets(1).Cells.NumberFormat = "#"
Range("B5") = Replace(Range("B5"), "_", ".")
End Sub
Formatting to text can work like this, for bigger, unknown ranges:
Sub TestMe()
Worksheets(1).Cells.NumberFormat = "General"
Range("A1:B15") = "05_2018"
Dim findRange As Range
Set findRange = Worksheets(1).Cells.Find("_")
Dim myCell As Range
If Not findRange Is Nothing Then
For Each myCell In findRange
myCell.Replace "_", ","
Next myCell
End If
End Sub

Search for a string in a Worksheet using VBA

I am trying to search for a particular string "ERROR" in all the worksheets in the workbook and make it bold and color the found cell red.
I am able to parse through each worksheet. I am not able to use the Find function of VBA.
Here's an example of using Find and formatting the found cells
Sub FindERROR()
Dim SearchString As String
Dim SearchRange As Range, cl As Range
Dim FirstFound As String
Dim sh As Worksheet
' Set Search value
SearchString = "ERROR"
Application.FindFormat.Clear
' loop through all sheets
For Each sh In ActiveWorkbook.Worksheets
' Find first instance on sheet
Set cl = sh.Cells.Find(What:=SearchString, _
After:=sh.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
If Not cl Is Nothing Then
' if found, remember location
FirstFound = cl.Address
' format found cell
Do
cl.Font.Bold = True
cl.Interior.ColorIndex = 3
' find next instance
Set cl = sh.Cells.FindNext(After:=cl)
' repeat until back where we started
Loop Until FirstFound = cl.Address
End If
Next
End Sub
if you are searching in excel vba you can use following simple code with InStr command.
Private Sub CommandButton1_Click()
Dim RowNum As Long
RowNum = 1
Do Until Sheets("Data").Cells(RowNum, 1).Value = ""
If InStr(1, Sheets("Data").Cells(RowNum, 2).Value, TextBox1.Value, vbTextCompare) > 0 Then
On erro GoTo next1
ListBox1.AddItem Sheets("Data").Cells(RowNum, 1).Value
ListBox1.List(ListBox1.ListCount - 1, 1) = Sheets("Data").Cells(RowNum, 2).Value
End If
next1:
RowNum = RowNum + 1
Loop
End Sub
you can download example file from here
How about this:
If Not WorkBook.Sheets("Sheet1").Range("A1:Z150").Find("Cookie") Is Nothing
MsgBox "Found a Cookie"
End If

Change a String to Uppercase if it Exists - VBA

How do I change a particular string to Uppercase only if it exists.
If (Cells(i, "A") Like "*roada*") Or (Cells(i, "A") Like "*roadb*") _
Or (Cells(i, "A") Like "*roadc*") etc... Then 'Change only the found string to Uppercase.
Each cell contains two or more words. Example: Cell A1 consists of "roadhouse blues". I want only 'roadh' to change to Uppercase if it exists in that cell. Is this possible in VBA?
This will do the trick:
Const road As String = "road"
Dim s As String
Dim letterAfterRoad As String
s = "play that roadhouse blues" ' or get contents of some cell
letterAfterRoad = Mid(s, InStr(s, road) + Len(road), 1)
Mid(s, InStr(s, road)) = UCase(road & letterAfterRoad)
Debug.Print s ' returns "play that ROADHouse blues". Write to cell.
If I were you, I would heed #minitech's sarcastic remark. If what you're looking for is road? where ? is a letter a-z then let Like look for a-z rather than manually typing the entire alphabet...
Here is how I would do it:
Const road As String = "road"
Dim s As String
Dim charAfterRoad As String
Dim roadPos As Long
s = "play that roadhouse blues"
roadPos = InStr(s, road)
If roadPos > 0 And Len(s) >= roadPos + Len(road) Then
'Found "road" and there is at least one char after it.
charAfterRoad = Mid(s, roadPos + Len(road), 1)
If charAfterRoad Like "[a-z]" Then
Mid(s, InStr(s, road)) = UCase(road & charAfterRoad)
End If
End If
Debug.Print s ' returns "play that ROADHouse blues"
Here is another way. Let Excel do the dirty work ;)
Sub Sample()
Dim SearchString As String
Dim ReplaceString As String
Dim aCell As Range
'~~> Search String
SearchString = "roadh"
'~~> Replace string
ReplaceString = UCase(SearchString)
'~~> Change A1 to to the respective cell
Set aCell = Range("A1").Find(What:=SearchString, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
'~~> If Found
If Not aCell Is Nothing Then
Range("A1").Replace What:=SearchString, Replacement:=ReplaceString, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
End If
End Sub
Also instead of looping you might want to use .FIND/.FINDNEXT ?
More on 'Find/FindNext': http://www.siddharthrout.com/index.php/2018/01/05/find-and-findnext-in-excel-vba/
FIND/FINDNEXT is far much more faster then looping and searching for values in Excel Cells ;)
AND the below is even faster (in fact the fastest). You don't need to find the word if your final intention is to replace the word. Simply issue the replace command. If the code finds any word then it will automatically replace.
Sub Sample()
Dim SearchString As String
Dim ReplaceString As String
'~~> Search String
SearchString = "roadh"
'~~> Replace string
ReplaceString = UCase(SearchString)
'~~> Replace the range below with the respective range
Range("A1:A1000").Replace What:=SearchString, Replacement:=ReplaceString, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
End Sub
You don't need to use the wildcard character to check for the presence of a string inside a string. xlPart in "LookAt:=xlPart" takes care of that :)
FOLLOWUP (In Case the user meant this)
You may be missing the point here... OP is not only looking for roadh but for any road? where ? is a letter a-z. You have to figure out what ? is and make it uppercase. That's the (mildly) interesting twist of this problem. – Jean-François Corbett 1 hour ago
Also checking for the scenario where the cell can contain multiple "road" values (as shown in snapshot below which has a 'before' and 'after' snapshot.
Sub Sample()
Dim oRange As Range, aCell As Range, bCell As Range
Dim ws As Worksheet
Dim ExitLoop As Boolean
Dim SearchString As String, FoundAt As String
On Error GoTo Whoa
Set ws = Worksheets("Sheet1")
Set oRange = ws.Columns(1)
SearchString = "road"
Set aCell = oRange.Find(What:=SearchString & "?", LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
FoundAt = aCell.Address
aCell.Value = repl(aCell.Value, SearchString)
Do While ExitLoop = False
Set aCell = oRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
FoundAt = FoundAt & ", " & aCell.Address
aCell.Value = repl(aCell.Value, SearchString)
Else
ExitLoop = True
End If
Loop
MsgBox "The Search String has been found these locations: " & FoundAt & " and replaced by UPPERCASE"
Else
MsgBox SearchString & " not Found"
End If
Exit Sub
Whoa:
MsgBox Err.Description
End Sub
Function repl(cellValue As String, srchString As String) As String
Dim pos As Integer
pos = InStr(1, cellValue, srchString, vbTextCompare)
repl = cellValue
Do While pos <> 0
If pos = 1 Then
repl = UCase(Left(repl, Len(srchString) + 1)) & Mid(repl, Len(srchString) + 2)
Else
repl = Mid(repl, 1, pos - 1) & UCase(Mid(repl, pos, Len(srchString) + 1)) & _
Mid(repl, pos + Len(srchString) + 1)
End If
Debug.Print repl
pos = InStr(pos + 1, repl, srchString, vbTextCompare)
Loop
End Function
Snapshot:
HTH
Sid
A way with a regexp, replaces all Road* in the input.
Sub repl(value As String)
Dim re As Object: Set re = CreateObject("vbscript.regexp")
Dim matches As Object, i As Long
re.IgnoreCase = True
re.Global = True
re.Pattern = "(road[A-Z])"
Set matches = re.Execute(value)
For i = 0 To matches.Count - 1
value = Replace$(value, matches(i), UCase$(matches(i)))
Next
Debug.Print value
End Sub

Resources