The main problem started when I wanted to "convert to number" by the green triangle (I know I can do it by hand, but there are a lot of cells like that and in the future I only want to use code).
So I wanted to do it by code, and I came across with this code that helps, but I have a problem with the number format which removes the decimal numbers.
Sub Valor3()
Dim LastRow As Long, i As Long
LastRow = Sheets("Hoja3").Range("A" & Rows.Count).End(xlUp).Row
'Sheets("Hoja3").Range("A1:A" & LastRow).NumberFormat = "# ##0,00"
For i = 1 To LastRow
If Val(Sheets("Hoja3").Range("A" & i).Value) <> 0 Then _
Sheets("Hoja3").Range("A" & i).Formula = _
Val(Sheets("Hoja3").Range("A" & i).Value)
Next i
End Sub
I've been trying many formats but none of them seems to help.
It might be because here we use the comma as a decimal separator and there is no miles separator.
What number format would help me?
The issue is that you use Val function in combination with a non-us-english decimal separator, which is not a proper solution to your issue.
The Val function recognizes only the period ( .) as a valid decimal separator. When different decimal separators are used, as in international applications, use CDbl instead to convert a string to a number.
Source: Microsoft documentation Val function.
Since the Val function does not convert a text into a value but extracts
The Val function only works with a dot . as decimal separator.
Example:
Val("2.55") 'will return 2.55 as number
Val("2,55") 'will return 2 as number (because it cuts off all text and the comma is not considered as decimal separator)
To get rid of the green triangle and convert a number that is saved as text into a real number properly, use the following:
Option Explicit
Public Sub ConvertNumberAsTextIntoRealNumber()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Hoja3")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
With ws.Range("A1", "A" & LastRow)
.NumberFormat = "# ##0.00" 'set your desired number format
.Value = .Value 'this will in most cases already convert to real numbers.
End With
'But if your numbers are hard coded to text and begin with a `'` you need the following additionally:
Dim iRow As Long
For iRow = 1 To LastRow
With ws.Cells(iRow, "A")
If IsNumeric(.Value) Then 'can the value be interpreted as a number
If .Value <> 0 Then 'is the value not zero
.Value = CDbl(.Value) 'then convert it into a real number
End If
End If
End With
Next iRow
End Sub
I know you are looking for VBA solution, but here's a small Excel trick that you might find useful:
Enter 1 (numeric value) somewhere in the file and copy it:
Select your range (A1:A6) and go to Paste > Paste Special > select Multiply:
The final result is all your text values being converted to numbers:
The same trick will work with other combinations, e.g. Operation: Add while having 0 copied, etc.
Related
I have an excel file with four columns: name, surname, address, area.
There are a lot of rows.
Is there a way to concatenate all the values of every single row in a variable, using vba?
I need a variable that should contain something like this:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3)...
If you have the following data in your worksheet
Then the following code will read the data into an array …
Option Explicit
Public Sub Example()
Dim RangeData() As Variant ' declare an array
RangeData = Range("A1:D5").Value2 ' read data into array
End Sub
… with the following structure:
Alternatively you can do something like
Public Sub Example()
Dim DataRange As Range
Set DataRange = Range("A2:D5")
Dim RetVal As String
Dim Row As Range
For Each Row In DataRange.Rows
RetVal = RetVal & "(" & Join(Application.Transpose(Application.Transpose(Row.Value2)), ",") & "); "
Next Row
Debug.Print RetVal
End Sub
To get this output:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3); (name4, surname4, address4, area4);
.. is there a way to write the result like a sort of list that shows all the values of the cells of the range?
Yes, there is. In addition to PEH's valid answers and disposing of Excel version MS365 you might also use
Dim s as String
s = Evaluate("ArrayToText(A2:D5, 1)") ' arg. value 1 representing strict format
resulting in the following output string:
{"name1","surname1","address1","area1";"name2","surname2","address2","area2";"name3","surname3","address3","area3";"name4","surname4","address4","area4"}
Syntax
ARRAYTOTEXT(array, [format])
The ARRAYTOTEXT function returns an array of text values from any specified range. It passes text values unchanged, and converts non-text values to text.
The format argument has two values, 0 (concise default format) and 1 (strict format to be used here to distinguish different rows, too):
Strict format, i.e. value 1 includes escape characters and row delimiters. Generates a string that can be parsed when entered into the formula bar. Encapsulates returned strings in quotes except for Booleans, Numbers and Errors.
Thank you for your answers, suggestions, ideas and hints. I am sorry if my question was not so clear, all the solutions you added were perfect and extremely elegant.
In the end I found a way - a dumber way in comparison to all the things you wrote - and I solved with a for statement.
I did like this:
totRow = ActiveSheet.UsedRange.Rows.Count
For i = 1 To totRow
name = Cells(i, 1)
surname = Cells(i, 2)
address = Cells(i, 3)
area = Cells(i, 4)
Example = Example & "(" & name & ", " & surname & ", " & address & ", " & area & "); "
Next i
Range("E1").Value = Example
It works (it does what I wanted to do), but I noticed a little limit: if the rows are a lot I can't keep the whole text in the variable.
There seems to be lots of similar questions but nothing that quite seems to answer this one.
I have created the below sub to convert a column of text to dates. It works in some scenarios, i.e. where the date has 8 characters such as 10022017, but not if the value has 7 characters such as 1022017.
Any ideas appreciated.
Sub convertDate()
'Find the last Row with data in a Column
Dim lastRow As Long
Dim i As Long
With ActiveSheet
lastRow = .Cells(.Rows.Count, ColumnSelect).End(xlUp).Row
End With
'convert column from string to date
For i = RowSelect To lastRow
Cells(i, ColumnSelect).Value = Format(Cells(i, ColumnSelect).Value, "00/00/0000")
Next i
End Sub
Hi again all, still having a few problems, the ideal formula seems to be =DATEVALUE(TEXT(A1,"00-00-0000")) if for example A1 = e.g. 02022017. Still haven't found the best way to do this with VBA as everything seems to run up against the truncated zeros problem. Thanks in advance
If your format is going to be consistent then try this.
This adds a 0 before Cells(i, ColumnSelect).Value when there are 7 characters.
For i = RowSelect To lastRow
Select Case Len(Trim(Cells(i, ColumnSelect).Value))
Case 8
Cells(i, ColumnSelect).Value = Format(Cells(i, ColumnSelect).Value, "00/00/0000")
Case 7
Cells(i, ColumnSelect).Value = Format("0" & _
Cells(i, ColumnSelect).Value, "00/00/0000")
End Select
Next i
But be careful with numbers like 1122017... this can be 11/2/2017 or 1/12/2017
Edit
Looking at 10022017, I realised that 1122017 will be 1/12/2017 and not 11/2/2017 as your mm zeros are not getting truncated.
OP wants a formula as well
=IF(LEN(A1)=8,TEXT(DATEVALUE(LEFT(A1,2)&"/"&MID(A1,3,2)&"/"&RIGHT(A1,4)),"dd/mm/yyyy"),TEXT(DATEVALUE(LEFT(A1,1)&"/"&MID(A1,2,2)&"/"&RIGHT(A1,4)),"dd/mm/yyyy"))
I want to use VBA to split the contents of a cell into three separate parts, such as [city], [state] [zip code] are put into three different columns on the same row while leaving the original cell unchanged.
I had thought that split would work, but unfortunately I have encountered some complicating issues, first split seems to only carry over the what's on the left, leaving behind the rest, second, I don't see how I can incorporate two delimiters into a single split.
Any idea how to surmount these issues?
Cells(Row1, ColA).Select
Location = ActiveCell.Value
Cells(Row1, ColC) = Split(Location, ",")
Cells(Row1, ColA).Select
Cells(Row1, ColD) = Split(Location, " ")
Cells(Row1, ColA).Select
Cells(Row1, ColE) = Split(Location, " ")
Split() returns an array of strings, you need to iterate through this array and assign the value of each element to the corresponding cell (take a look at this answer).
Also, you don't need to select cells to assign values to it, you may use:
Cells(Row,Column).Value = X
Regarding 2 delimiters, you may do it as described here.
Use the Split, I use an array in the middle just to store the split String (in case you will want to use it later), it also saves me the time of the iteration.
Sub Split_toThree()
Dim lrow As Long
Dim LastRow As Long
Dim SplitArr() As String
' find last row in Column A (where you keep your full string)
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
For lrow = 2 To LastRow
SplitArr() = Split(Cells(lrow, "a"), ",")
Range("C" & lrow & ":E" & lrow) = SplitArr()
Next lrow
End Sub
I have a longstanding formatting frustration. I often do this manually but doing it manually takes forever, and there has to be a way to do this with either a VBA macro, conditional formatting or a clever number format.
Below is my desired result. It has the following properties:
The largest number in the column (in this case the last number in the column, $103,420) is centered within the cell.
The largest number in the cell is not, however, center aligned, it is right indented until the value is centered.
All other numbers in the column are also right indented an equal amount. This is desirable because it lines up the ones place, tens place etc. in each number.
Negative numbers are denoted surrounded by parentheses.
The dollar sign is adjacent to the leftmost number.
Commas are included properly for numbers greater than 999.
This result was achieved by:
Applying the following number format:$#,##0_);($#,##0)_);$0_);#_)
Manually adjusting the right indent of the cell on the largest number to determine when it is roughly centered. If more space must be on one side or the other, the larger space is left on the left side of the number.
I attempted to apply a number format similar to the one used in response to this question.
Specifically my attempt at using this was to center align all cells using the following number format: $?,??0;($?,??0);
That produces the following close but not quite result below.
Thoughts on how I can address this? I'm imagining a macro that identifies the largest number in the selection, gets the number of digits in that number, the font size, the width of the column, does some computation yielding the desired right indent and then applies the right indent. I'm just not sure how to do that kind of computation.
'Select your data range, and run formatCells_Accounting(). The number formatting in the selected cells will widen to the cell with the longest value. Note, the macro does not work on values greater than 10^14 (not sure why.)
Sub formatCells_Accounting()
Dim rg As Range
Set rg = Selection
maxVal = Application.WorksheetFunction.Max(rg)
minVal = Application.WorksheetFunction.Min(rg)
If Abs(minVal) > maxVal Then
longest_ = minVal
Else
longest_ = maxVal
End If
lenLongest = Len(CStr(Round(longest_, 0)))
rg.NumberFormat = "_($" & addCommasToFormat(lenLongest) & "_);" & _
"_(($" & addCommasToFormat(lenLongest) & ");" & _
"_($" & addCommasToFormat(lenLongest - 1) & "0_);" & _
"_(#_)"
End Sub
Function addCommasToFormat(ByVal lenLongest) As String
str_ = String(lenLongest, "?")
new_str_ = ""
For i = 1 To Len(str_)
If i Mod 3 = 1 And i <> 1 Then
new_str_ = new_str_ & ",?"
Else
new_str_ = new_str_ & "?"
End If
Next
addCommasToFormat = StrReverse(new_str_)
End Function
Chris - your answer doesn't do what I was hoping for (your answer leaves space between the dollar sign and the "last" digit for numbers shorter than the longest number in the set)
However, your code was a helpful starting point for this solution I've come up with. The result is shown in the image below along with the inherent downside to this solution - running a formula on the numbers in the column after they've been formatted in this way results in a weird number format.
The only solution I can come up with that doesn't have the problem this solution does is, one that relies on estimating an indent, and applying it. That solution only works so long as the column width is not adjusted going forwards. If it is adjusted the macro would have to be re-run. Additionally, because the indent can only be increased by an increment of 1 (and nothing less), a macro that applied an indent would typically result in the largest number in the column not being exactly centered. Not a huge deal but my current solution doesn't have either of these problems and in my use case, these formats are being applied as the last step in the process of formatting a spreadsheet so additional calculations aren't likely to happen and if they do, the macro can simply be re-run as needed.
'Select your data range, and run formatCells_Accounting(). The number formatting in the selected cells will widen to the cell with the longest value. Note, the macro does not work on values greater than 10^14 (not sure why.)
Sub formatCells_Accounting()
Dim rg, thisColRange, rCell As Range
Dim maxVal, minVal, valueLen, longest_, lenLongest As Long
Set rg = Selection
'Center aligns all selected cells
rg.HorizontalAlignment = xlCenter
'Loops through each column in the selected range so that each column can have it's own max value
For Each thisColRange In rg.Columns
maxVal = Application.WorksheetFunction.Max(thisColRange)
minVal = Application.WorksheetFunction.Min(thisColRange)
'The longest number in the range may be the most negative
'This if section accounts for this scenario
If Abs(minVal) > maxVal Then
longest_ = minVal
Else
longest_ = maxVal
End If
'Gets the length of the longest value rounded to the ones place (aka length not including decimals)
lenLongest = Len(CStr(Round(Abs(longest_), 0)))
'Creates a number format for every cell
For Each rCell In thisColRange.Cells
'Gets the length of the value in the current cell
valueLen = Len(CStr(Round(Abs(rCell.Value), 0)))
rCell.NumberFormat = "_(" & addCommasDollarsToFormat(lenLongest, valueLen, rCell.Value) & "_);" & _
"_(" & addCommasDollarsToFormat(lenLongest, valueLen, rCell.Value) & ")_);" & _
"_(" & Left(addCommasDollarsToFormat(lenLongest, 1, rCell.Value), Len(addCommasDollarsToFormat(lenLongest, 1, rCell.Value)) - 1) & "0_);" & _
"_(#_)"
Next
Next
End Sub
Function addCommasDollarsToFormat(ByVal lenLongest, ByVal valueLen, ByVal cellVal) As String
Dim new_str_ As String
Dim i, j As Long
'Initializes empty strings
new_str_ = ""
nearlyFinishedString = ""
'Adds ? and , through the length of the value currently being formatted
For i = 1 To valueLen
If i Mod 3 = 1 And i <> 1 Then
new_str_ = new_str_ & ",?"
Else
new_str_ = new_str_ & "?"
End If
Next
If cellVal < 0 Then
new_str_ = new_str_ & "$("
Else
new_str_ = new_str_ & "$"
End If
For j = i To lenLongest
If j Mod 3 = 1 Then
new_str_ = new_str_ & ",?"
Else
new_str_ = new_str_ & "?"
End If
Next
addCommasDollarsToFormat = StrReverse(new_str_)
End Function
Solution visualized with the downside of the solution shown below it.
Please be aware that I am working with a series of ~1000 line medical information databases. Due to the size of the databases, manual manipulation of the data is too time consuming. As such, I have attempted to learn VBA and code an Excel 2010 macro using VBA to help me accomplish parsing certain data. The desired output is to split certain characters from a provided string on each line of the database as follows:
99204 - OFFICE/OUTPATIENT VISIT, NEW
will need to be split into
Active Row Active Column = 99204 ActiveRow Active Column+3 = OFFICE/OUTPATIENT VISIT, NEW
I have researched this topic using Walkenbach's "Excel 2013: Power Programming with VBA" and a fair amount of web resources, including this awesome site, but have been unable to develop a fully-workable solution using VBA in Excel. The code for my current macro is:
Sub EasySplit()
Dim text As String
Dim a As Integer
Dim name As Variant
text = ActiveCell.Value
name = Split(text, "-", 2)
For a = 0 To 1
Cells(1, a + 3).Value = Trim(name(a))
Next a
End Sub
The code uses the "-" character as a delimiter to split the input string into two substrings (I have limited the output strings to 2, as there exists in some input strings multiple "-" characters). I have trimmed the second string output to remove leading spaces.
The trouble that I am having is that the output is being presented at the top of the activesheet, instead of on the activerow.
Thank you in advance for any help. I have been working on this for 2 days and although I have made some progress, I feel that I have reached an impasse. I think that the issue is somewhere in the
Cells(1, a + 3).Value = Trim(name(a))
code, specifically with "Cells()".
Thank you Conrad Frix!
Yah.. funny enough. Just after I post I have a brainstorm.. and modify the code to read:
Sub EasySplit()
Dim text As String
Dim a As Integer
Dim name As Variant
text = ActiveCell.Value
name = Split(text, "-", 2)
For a = 0 To 1
ActiveCell.Offset(0, 3 + a).Value = Trim(name(a))
Next a
End Sub
Not quite the colkumn1,column4 output that I want (it outputs to column3,column4), but it will work for my purpose.
Now I need to incorporate a loop so that the code runs on each successive cell in the column (downwards, step 1) skipping all bolded cells, until it hits an empty cell.
Modified answer to modified request.
This will start on row 1 and continue until a blank cell is found in column A. If you would like to start on a different row, perhaps row 2 if you have headers, change the
i = 1
line to
i = 2
I added a check on the upper bound of our variant before doing the output writes, in case the macro is run again on already formatted cells. (Does nothing instead of erroring out)
Sub EasySplit()
Dim initialText As String
Dim i As Double
Dim name As Variant
i = 1
Do While Trim(Cells(i, 1)) <> ""
If Not Cells(i, 1).Font.Bold Then
initialText = Cells(i, 1).text
name = Split(initialText, "-", 2)
If Not UBound(name) < 1 Then
Cells(i, 1) = Trim(name(0))
Cells(i, 4) = Trim(name(1))
End If
End If
i = i + 1
Loop
End Sub
just add a variable to keep track of the active row and then use that in place of the constant 1.
e.g.
Dim iRow as Integer = ActiveCell.Row
For a = 0 To 1
Cells(iRow , a + 3).Value = Trim(name(a))
Next a
Alternate method utilizing TextToColumns. This code also avoids using a loop, making it more efficient and much faster. Comments have been added to assist with understanding the code.
EDIT: I have expanded the code to make it more versatile by using a temp worksheet. You can then output the two columns to wherever you'd like. As stated in your original question, the output is now to columns 1 and 4.
Sub tgr()
Const DataCol As String = "A" 'Change to the correct column letter
Const HeaderRow As Long = 1 'Change to be the correct header row
Dim rngOriginal As Range 'Use this variable to capture your original data
'Capture the original data, starting in Data column and the header row + 1
Set rngOriginal = Range(DataCol & HeaderRow + 1, Cells(Rows.Count, DataCol).End(xlUp))
If rngOriginal.Row < HeaderRow + 1 Then Exit Sub 'No data
'We will be using a temp worksheet, and to avoid a prompt when we delete the temp worksheet we turn off alerts
'We also turn off screenupdating to prevent "screen flickering"
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'Move the original data to a temp worksheet to perform the split
'To avoid having leading/trailing spaces, replace all instances of " - " with simply "-"
'Lastly, move the split data to desired locations and remove the temp worksheet
With Sheets.Add.Range("A1").Resize(rngOriginal.Rows.Count)
.Value = rngOriginal.Value
.Replace " - ", "-"
.TextToColumns .Cells, xlDelimited, Other:=True, OtherChar:="-"
rngOriginal.Value = .Value
rngOriginal.Offset(, 3).Value = .Offset(, 1).Value
.Worksheet.Delete
End With
'Now that all operations have completed, turn alerts and screenupdating back on
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
You can do this in a single shot without looping using the VBA equivalent of entering this formula, then taking values only
as a formula
=IF(NOT(ISERROR(FIND("-",A1))),RIGHT(A1,LEN(A1)-FIND("-",A1)-1 ),A1)
code
Sub Quicker()
Dim rng1 As Range
Set rng1 = Range([a1], Cells(Rows.Count, "A").End(xlUp))
With rng1.Offset(0, 3)
.FormulaR1C1 = "=IF(NOT(ISERROR(FIND(""-"",RC[-3]))),RIGHT(RC[-3],LEN(RC[-3])-FIND(""-"",RC[-3])-1 ),RC[-3])"
.Value = .Value
End With
End Sub