Trimming spaces - excel

I'm trying to parse left and right empty spaces, nbsp, \n, \t, etc. from all Excel cells in a certain range.
I'm using the following macro:
Sub TRIM_CELLS()
'Clean all conditional formating
Cells.FormatConditions.Delete
'improve performance
Application.ScreenUpdating = False
Dim all_cells_range As String
all_cells_range = "A1:A10"
'Trim all those cells
Range(all_cells_range).Select
For Each cell In Selection.Cells
cell.Value = Application.Substitute(Application.Substitute(CStr(cell.Value), vbLf, vbCr), vbCr, "")
cell = WorksheetFunction.Trim((Application.Clean(Replace(cell.Value, Chr(160), " "))))
Next cell
End Sub
Something like "Maria Tavares " doesn't get trimmed properly.

#Nick: I tried to use your idea and I think the problem is the char itself... Assuming the following loop works as expected I would get the char that is causing the problem.
Take a look at this image:
But nothing gets printed in that place.
Sub TRIM_CELLS()
'Clean all conditional formating
Cells.FormatConditions.Delete
'improve performance
Application.ScreenUpdating = False
Dim all_cells_range As String
all_cells_range = "A1:A2"
'Trim all those cells
Range(all_cells_range).Select
For Each cell In Selection.Cells
For I = 1 To 255
cell = WorksheetFunction.Substitute(cell, Chr(I), I)
Next I
Next cell
End Sub

I use a function that removes any special characters that you define.
Function RemoveSpecialCharacters(wks As Worksheet, strRange As String, var As Variant)
Dim rngAddress As Range, cell As Range, I&
'e.g strRange - "E2:E"
With wks
Set rngAddress = .Range(strRange & .Cells(Rows.count, "A").End(xlUp).row)
For I = LBound(var) To UBound(var)
For Each cell In rngAddress
cell = WorksheetFunction.Substitute(cell, var(I), " ")
Else
cell = WorksheetFunction.Substitute(cell, var(I), "")
Next cell
Next I
End With
End Function
You could call the function like this:
RemoveSpecialCharacters worksheetname, "A1:A", Array(Chr(9), Chr(10), Chr(13), Chr(39))
Where Chr(10) is linefeed character, chr(9) is the tab character etc.
See this link for what other Chr codes stand for.
UPDATE:
Try this to remove the weird "spy" character from the cell.
RemoveSpecialCharacters worksheetname, "A1:A", Array(Chr(160))

Ended up doing a replacement with that "space"... not a great solution but fixed my problem... Just would like to know what char it was...
Sub TRIM_CELLS()
'Clean all conditional formating
Cells.FormatConditions.Delete
'improve performance
Application.ScreenUpdating = False
Dim all_cells_range As String
all_cells_range = "A1:A2"
Range(all_cells_range).Select
For Each cell In Selection.Cells
cell.Replace What:=" ", Replacement:=" ", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
cell.Value = Application.Substitute(Application.Substitute(CStr(cell.Value), vbLf, vbCr), vbCr, "")
cell.Value = WorksheetFunction.Trim(cell)
Next cell
end sub

Related

Excel VBA, how to achieve this formatting? Nmbr with commas and rounding to 2 decimal

So if we have a number, 99999.23412343 I'm hoping to get it to display 99,999.23 In other words, having a thousands separator comma and 2 decimal places rounded.
I have this code here, which makes values cosmetically look that way, but it doesn't actually round the number. is there a way to add rounding to this calculation or make the values themselves be 2 decimals?
Sub roundcode()
Columns("G:G").Select
Selection.NumberFormat = "_(* #,##0.00_);_(* (#,##0.00);_(* ""-""??_);_(#_)"
End Sub
This will apply both actual rounding as well as format rounding:
Sub roundd()
Dim rng As Range, cell As Range
Set rng = Intersect(Columns("G:G"), ActiveSheet.UsedRange)
With Application.WorksheetFunction
For Each cell In rng
If cell.HasFormula Then
txt = "(" & Mid(cell.Formula, 2) & ")"
cell.Formula = "=ROUND(" & txt & ",2)"
Else
cell.Value = .Round(cell.Value, 2)
End If
Next cell
End With
rng.NumberFormat = "#,000.00"
End Sub
It will handle both formulas and constants.
EDIT#1:
to avoid the first row, replace:
Columns("G:G")
with something like:
Range("G2:G999999")
EDIT#2:
Try this instead:
Sub roundd()
Dim rng As Range, cell As Range
Set rng = Intersect(Range("G2:G999999"), ActiveSheet.UsedRange)
With Application.WorksheetFunction
For Each cell In rng
If cell.HasFormula Then
txt = "(" & Mid(cell.Formula, 2) & ")"
cell.Formula = "=ROUND(" & txt & ",2)"
Else
If cell.Value <> "" Then
cell.Value = .Round(cell.Value, 2)
End If
End If
Next cell
End With
rng.NumberFormat = "#,000.00"
End Sub
I have no idea what that format is supposed to do. If you want thousands with two decimal places simply use:
Columns("G:G").NumberFormat = "#,000.00"
No need to Select to format. For a good reference for all number, time, date formats use the following link https://peltiertech.com/Excel/NumberFormats.html

How do you get Excel VBA to recognize numeric cells?

I have a table of numbers that are all left aligned (i.e. Excel recognizes them as text)
I run a VBA script on all cells:
cell.value = cell.Value * 1
This right aligns all of them and Excel recognized them as numbers except for decimals (e.g. 3.14 does not work while 314 works). I also run a find and replace script, where the search is for space (" ") and replace it with a blank(""), so this should get rid of atleast the common space.
Further clues: If i perform the =Value(A1) formula in Excel, Excel will recognize even the decimals as a number. If I run Workbookfunction.value(A1) Excel will not recognize as a number.
So the problem seems ro be related to VBA (?) and decimals. Any solutions?
I now ran the following after comments here:
For Each cell In rng
Dim vNumber As Double
On Error Resume Next
'Remove space
cell.Replace What:=" ", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
'Remove comma
cell.Replace What:=",", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
'Check if empty, if it is: Do nothing
If IsEmpty(cell) = True Then
Else
vNumber = CDbl(cell.Value)
cell.Value = vNumber
End If
'Check if numeric
If IsNumeric(cell) = True Then
cell.Interior.Color = RGB(0, 254, 0)
cell.Interior.TintAndShade = 0.8
Else
cell.Interior.Color = RGB(100, 0, 0)
cell.Interior.TintAndShade = 0.8
End If
Next cell
The result is the following Before and After (where one is with Double and other with Variant. Somehow its writing over cells that are not decimals...
You need to convert the value of the cell to a double. For example:
Dim myDouble As Double
myDouble = CDbl(Range("A1").Value)
Debug.Print myDouble
myDouble = myDouble + 1
Debug.Print myDouble
Lines 3 to 5 are just to demonstrate that it gets recognised as a decimal.
Did you try conversion?
Sub test()
Dim rng As Range, cell As Range
With ThisWorkbook.Worksheets("Sheet1")
Set rng = .Range("A1:A5")
For Each cell In rng
.Range("B" & cell.Row).Value = CDbl(cell)
Next cell
End With
End Sub
Results:
Val(Cells(1,1).Value will convert a string to a number if it's numeric, to zero if it's not. "123abc" will be converted to the number 123. IsNumeric(Cells(1,1).Value) will return True if there are no non-numeric characters in the cell's string.
Incidentally, VBA's Val() function will ignore blanks. Val(123 456") will return the number 123456.
The code below will meet your updated requirements. Please try it.
Sub ConvertTextToNumbers()
Dim Rng As Range
Dim Cell As Range
Dim Arr As Variant
Dim R As Long
With Worksheets("Sheet1") ' modify to suit
Set Rng = .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp))
Arr = Rng.Value
For R = 1 To UBound(Arr)
' remove commas and spaces
Arr(R, 1) = Val(Replace(Replace(Arr(R, 1), " ", ""), ",", ""))
Next R
Rng.Offset(0, 1).Value = Arr
For Each Cell In Rng.Offset(0, 1)
Cell.Interior.Color = IIf(Cell.Value, vbGreen, vbRed)
Next Cell
End With
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

Use Find/Replace to clear vbNullString

I have a spreadsheet that is generated as a report in our Enterprise system and downloaded into an Excel spreadsheet. Blank cells in the resulting spreadsheet are not really blank, even though no data is present - and the blank cells do Not contain a 'space' character.
For example, the following cell formula in A2 returns TRUE (if A1 is a blank cell):
=IF(A1="","TRUE","FALSE")
However,
=ISBLANK(A1)
returns FALSE.
You can replicate this problem by typing an apostrophe (') in a cell and copying the cell. Then, use Paste Special...Values to paste to another cell and the apostrophe is not visible in the pasted cell, nor in the Formula Bar. There appears to be a clear cell, but it will evaluate to FALSE using ISBLANK.
This causes sorting to result in the fake blank cells at the top of an ascending sort, when they need to be at the bottom of the sort.
I can use a vba loop to fix the fake blanks, to loop through every column and evaluate
IF Cell.VALUE = "" Then
Cell.Clear
but because the spreadsheet has tens of thousands of rows of data and as many as 50 columns, this adds substantial overhead to the program and I would prefer to use FIND and Replace.
Here is the code that does not currently work:
Range("ZZ1").Copy
Range("Table1[#All]").Select
With Selection
.Replace What:="", Replacement:=.PasteSpecial(xlPasteValues, xlNone, False, False), _
LookAt:=xlWhole, SearchOrder:=xlByColumns, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
End With
The following things do not work to clear the fake blank cells either:
Replacement:= vbnullstring
Replacement:= ""
Replacement:= Cells.Clear
Replacement:= Cells.ClearContents
Replacement:= Cells.Value = ""
I have tried 20 other things that do not work either.
Try this
With ActiveSheet.UsedRange
.NumberFormat = "General"
.Value = .Value
End With
A variant array provides an efficient way of handling the false empties:
Sub CullEm()
Dim lngRow As Long
Dim lngCol As Long
Dim X
X = ActiveSheet.UsedRange.Value2
For lngRow = 1 To UBound(X, 1)
For lngCol = 1 To UBound(X, 2)
If Len(X(lngRow, lngCol)) = 0 Then X(lngRow, lngCol) = vbNullString
Next
Next
ActiveSheet.UsedRange.Value2 = X
End Sub
The problem is that you are searching for a hidden .PrefixCharacter which are not covered by the standard replacement function. For more information on this you might want to visit MSDN: https://msdn.microsoft.com/en-us/library/office/ff194949.aspx
In order to find and replace these you'll have to use the .Find function because it can look at the formulas (rather than only at a cell's value). Here is a short sample code to illustrate that:
Option Explicit
Public Sub tmpTest()
Dim cell As Range
Dim rngTest As Range
Dim strFirstAddress As String
Set rngTest = ThisWorkbook.Worksheets(1).Range("A1:G7")
Set cell = rngTest.Find("", LookIn:=xlFormulas, lookat:=xlPart)
If Not cell Is Nothing Then
strFirstAddress = cell.Address
Do
cell.Value = vbNullString
Set cell = rngTest.FindNext(cell)
Loop While strFirstAddress <> cell.Address And Not cell Is Nothing
End If
End Sub
I can't figure out anything that you could put in Replacement to get that to work. I'm afraid you're stuck looping. You can reduce the overhead by using .Find instead of looping through every cell.
Sub ClearBlanks()
Dim rng As Range
Dim rFound As Range
Dim sFirstAdd As String
Dim rFoundAll As Range
Set rng = Sheet1.UsedRange
Set rFound = rng.Find(vbNullString, , xlValues, xlWhole)
If Not rFound Is Nothing Then
sFirstAdd = rFound.Address
Do
If rFoundAll Is Nothing Then
Set rFoundAll = rFound
Else
Set rFoundAll = Application.Union(rFound, rFoundAll)
End If
Set rFound = rng.FindNext(rFound)
Loop Until rFound.Address = sFirstAdd
End If
If Not rFoundAll Is Nothing Then
rFoundAll.ClearContents
End If
End Sub
You can use the table filter to select the (seemingly) blank cells in each column and clear the contents. This should be quicker than finding each blank cell.
Sub clearBlankTableEntries()
Dim tbl As ListObject, c As Byte
Set tbl = ActiveSheet.ListObjects("testTable")
For c = 1 To tbl.Range.Columns.Count
tbl.Range.AutoFilter Field:=c, Criteria1:="="
Range(tbl.Name & "[Column" & c & "]").ClearContents
tbl.Range.AutoFilter Field:=c
Next c
End Sub

Using "If cell contains" in VBA excel

I'm trying to write a macro where if there is a cell with the word "TOTAL" then it will input a dash in the cell below it. For example:
In the case above, I would want a dash in cell F7 (note: there could be any number of columns, so it will always be row 7 but not always column F).
I'm currently using this code, but it's not working and I can't figure out why.
Dim celltxt As String
Range("C6").Select
Selection.End(xlToRight).Select
celltxt = Selection.Text
If InStr(1, celltext, "TOTAL") > 0 Then
Range("C7").Select
Selection.End(xlToRight).Select
Selection.Value = "-"
End If
Help would be appreciated. Hopefully I'm not doing something stupid.
This will loop through all cells in a given range that you define ("RANGE TO SEARCH") and add dashes at the cell below using the Offset() method. As a best practice in VBA, you should never use the Select method.
Sub AddDashes()
Dim SrchRng As Range, cel As Range
Set SrchRng = Range("RANGE TO SEARCH")
For Each cel In SrchRng
If InStr(1, cel.Value, "TOTAL") > 0 Then
cel.Offset(1, 0).Value = "-"
End If
Next cel
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not Intersect(Target, Range("C6:ZZ6")) Is Nothing Then
If InStr(UCase(Target.Value), "TOTAL") > 0 Then
Target.Offset(1, 0) = "-"
End If
End If
End Sub
This will allow you to add columns dynamically and automatically insert a dash underneath any columns in the C row after 6 containing case insensitive "Total". Note: If you go past ZZ6, you will need to change the code, but this should get you where you need to go.
This does the same, enhanced with CONTAINS:
Function SingleCellExtract(LookupValue As String, LookupRange As Range, ColumnNumber As Integer, Char As String)
Dim I As Long
Dim xRet As String
For I = 1 To LookupRange.Columns(1).Cells.Count
If InStr(1, LookupRange.Cells(I, 1), LookupValue) > 0 Then
If xRet = "" Then
xRet = LookupRange.Cells(I, ColumnNumber) & Char
Else
xRet = xRet & "" & LookupRange.Cells(I, ColumnNumber) & Char
End If
End If
Next
SingleCellExtract = Left(xRet, Len(xRet) - 1)
End Function
Dim celltxt As String
Range("C6").Select
Selection.End(xlToRight).Select
celltxt = Selection.Text
If InStr(1, celltext, "TOTAL") > 0 Then
Range("C7").Select
Selection.End(xlToRight).Select
Selection.Value = "-"
End If
You declared "celltxt" and used "celltext" in the instr.
Is this what you are looking for?
If ActiveCell.Value == "Total" Then
ActiveCell.offset(1,0).Value = "-"
End If
Of you could do something like this
Dim celltxt As String
celltxt = ActiveSheet.Range("C6").Text
If InStr(1, celltxt, "Total") Then
ActiveCell.offset(1,0).Value = "-"
End If
Which is similar to what you have.
Requirement:
Find a cell containing the word TOTAL then to enter a dash in the cell below it.
Solution:
This solution uses the Find method of the Range object, as it seems appropriate to use it rather than brute force (For…Next loop).
For explanation and details about the method see Range.Find method (Excel)
Implementation:
In order to provide flexibility the Find method is wrapped in this function:
Function Range_ƒFind_Action(sWhat As String, rTrg As Range) As Boolean
Where:
sWhat: contains the string to search for
rTrg: is the range to be searched
The function returns True if any match is found, otherwise it returns False
Additionally, every time the function finds a match it passes the resulting range to the procedure Range_Find_Action to execute the required action, (i.e. "enter a dash in the cell below it"). The "required action" is in a separated procedure to allow for customization and flexibility.
This is how the function is called:
This test is searching for "total" to show the effect of the MatchCase:=False. The match can be made case sensitive by changing it to MatchCase:=True
Sub Range_Find_Action_TEST()
Dim sWhat As String, rTrg As Range
Dim sMsgbdy As String
sWhat = "total" 'String to search for (update as required)
Rem Set rTrg = ThisWorkbook.Worksheets("Sht(0)").UsedRange 'Range to Search (use this to search all used cells)
Set rTrg = ThisWorkbook.Worksheets("Sht(0)").Rows(6) 'Range to Search (update as required)
sMsgbdy = IIf(Range_ƒFind_Action(sWhat, rTrg), _
"Cells found were updated successfully", _
"No cells were found.")
MsgBox sMsgbdy, vbInformation, "Range_ƒFind_Action"
End Sub
This is the Find function
Function Range_ƒFind_Action(sWhat As String, rTrg As Range) As Boolean
Dim rCll As Range, s1st As String
With rTrg
Rem Set First Cell Found
Set rCll = .Find(What:=sWhat, After:=.Cells(1), _
LookIn:=xlFormulas, LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
Rem Validate First Cell
If rCll Is Nothing Then Exit Function
s1st = rCll.Address
Rem Perform Action
Call Range_Find_Action(rCll)
Do
Rem Find Other Cells
Set rCll = .FindNext(After:=rCll)
Rem Validate Cell vs 1st Cell
If rCll.Address <> s1st Then Call Range_Find_Action(rCll)
Loop Until rCll.Address = s1st
End With
Rem Set Results
Range_ƒFind_Action = True
End Function
This is the Action procedure
Sub Range_Find_Action(rCll)
rCll.Offset(1).Value2 = Chr(167) 'Update as required - Using `§` instead of "-" for visibilty purposes
End Sub

Resources