How to format multi-line cell of numbers in Excel? - excel

Given an Excel cell with multiple lines (text wrapping).
E.g.
5501.700
640.8690
1081.45600
41.100
I want to format all the numbers (in this single cell) to have 2 decimal places and thousand separators. What are my options to accomplish this task?

I think the only way is with a macro; read value, split each line, format, join.
ALT+F11, insert -> module and add;
Public Function FORMATLINES(cell As Range) As String
Dim data() As String, i As Long
data = Split(cell.Text, vbLf)
For i = 0 To UBound(data)
If IsNumeric(data(i)) Then data(i) = FormatNumber(data(i), 2, vbTrue, vbFalse, vbTrue)
Next
FORMATLINES = Join(data, vbLf)
End Function
For
=FORMATLINES(A1)
Gives me;
5,501.70
640.87
1,081.46
41.10

Related

Excel 2016 - Sort value in cell in ascending order

I currently have a cell with some values, separated by commas. I wish to sort them in ascending order.
Sample Input (Value in a single cell):
Sample Output (Value in a single cell):
I have seen many answers when it comes to sorting rows and columns, but I can't seem to sort the values in a single cell in ascending order. Is it possible to sort the values in a single cell in ascending order? Or is there a workaround for this?
Some explanation/documentation would be appreciated as I'm a beginner at VBA. Thank you for your help.
Please try to split data in a single cell by comma, then sorting it and combine all of them together?
The comments provide you with numerous ways to sort an array. Rightly or wrongly, I've provided my own flavour on an old VBA topic along with the extended piece of outputting the string in a delimited format. Take it or leave it ...!
You should be able to refer to the below function directly from any given cell like you would any built-in function in Excel.
Public Function SplitAndSortAscending(ByVal strText As String, ByVal strDelimiter As String) As String
Dim arrData() As String, arrNewData() As String, i As Long, x As Long, y As Long
arrData = Split(strText, strDelimiter)
ReDim arrNewData(UBound(arrData))
For i = 0 To UBound(arrData)
For x = 0 To UBound(arrNewData)
If arrData(i) < arrNewData(x) Or arrNewData(x) = "" Then
For y = UBound(arrNewData) To x + 1 Step -1
arrNewData(y) = arrNewData(y - 1)
Next
arrNewData(x) = arrData(i)
Exit For
End If
Next
Next
For i = 0 To UBound(arrNewData)
SplitAndSortAscending = SplitAndSortAscending & strDelimiter & arrNewData(i)
Next
SplitAndSortAscending = Mid(SplitAndSortAscending, Len(strDelimiter) + 1)
End Function
If you have O365, you can use something like the below to achieve the same sort of thing. Take note, my implementation will take 1.0 and format it as a whole number, i.e. it will come out as 1.
=TEXTJOIN(",",TRUE,SORT(FILTERXML("<r><v>" & SUBSTITUTE(A1,",","</v><v>") & "</v></r>","//v")))
The assumption is that the example you provided is in cell A1.

Summing the digits in Excel cells (long and short strings)

I'm working on a research related to frequencies.
I want to sum all the numbers in each cell and reduce them to single number only.
some cells have 2 numbers, others have 13 numbers. like these..
24.0542653897891
25.4846064424057
27
28.6055035477009
I tried several formulas to do that. the best ones have me 2 digits number, that I couldn't sum it again to get a single result.
like these Formulas:
=SUMPRODUCT(MID(SUBSTITUTE(B5,".",""),ROW(INDIRECT("1:"&LEN(B5)-1)),1)+0)
=SUMPRODUCT(1*MID(C5,ROW(INDIRECT("1:"&LEN(C5))),1))
any suggestion?
Thank you in advance.
EDIT
Based on your explanation your comments, it seems that what you want is what is called the digital root of the all the digits (excluding the decimal point). In other words, repeatedly summing the digits until you get to a single digit.
That can be calculated by a simpler formula than adding up the digits.
=1+(SUBSTITUTE(B5,".","")-1)-(INT((SUBSTITUTE(B5,".","")-1)/9)*9)
For long numbers, we can split the number in half and process each half. eg:
=1+MOD(1+MOD(LEFT(SUBSTITUTE(B5,".",""),INT(LEN(SUBSTITUTE(B5,".",""))/2))-1,9)+1+MOD(RIGHT(SUBSTITUTE(B5,".",""),LEN(SUBSTITUTE(B5,".",""))-INT(LEN(SUBSTITUTE(B5,".",""))/2))-1,9)-1,9)
However, the numbers should be stored as TEXT. When numbers are stored as numbers, what we see may not necessarily be what is stored there, and what the formula (as well as the UDF) will process.
The long formula version will correct all the errors on your worksheet EXCEPT for B104. B104 appears to have the value 5226.9332653096000 but Excel is really storing the value 5226.9333265309688. Because of Excel's precision limitations, this will get processed as 5226.93332653097. Hence there will be a disagreement.
Another method that should work would be to round all of the results in your column B to 15 digits (eg: . Combining that with using the long formula version should result in agreement for all the values you show.
Explanation
if a number is divisible by 9, its digital root will be 9, otherwise, the digital root will be n MOD 9
The general formula would be: =1+Mod(n-1,9)
In your case, since we are dealing with numbers larger than can be calculated using the MOD function, we need to both remove the dot, and also use the equivalent of mod which is n-(int(n/9)*9)
Notes:
this will work best with numbers stored as text. Since Excel may display and/or convert large numbers, or numbers with many decimal places, differently than expected, working with text strings of digits is the most stable method.
this method will not work reliably with numbers > 15 digits.
If you have numbers > 15 digits, then I suggest a VBA User Defined Function:
Option Explicit
Function digitalRoot(num As String) As Long
Dim S As String, Sum As Long, I As Long
S = num
Do While Len(S) > 1
Sum = 0
For I = 1 To Len(S)
Sum = Sum + Val(Mid(S, I, 1))
Next I
S = Trim(Str(Sum))
Loop
digitalRoot = CLng(S)
End Function
You could use a formula like:
=SUMPRODUCT(FILTERXML("<t><s>"&SUBSTITUTE(A1," ","</s><s>")&"</s></t>","//s"))
You might need an extra SUBSTITUTE for changing . to , if that's your decimal delimiter:
=SUMPRODUCT(FILTERXML("<t><s>"&SUBSTITUTE(SUBSTITUTE(A1,".",",")," ","</s><s>")&"</s></t>","//s"))
However, maybe a UDF as others proposed is also a possibility for you. Though, something tells me I might have misinterpreted your question...
I hope you are looking for something like following UDF.
Function SumToOneDigit(myNumber)
Dim temp: temp = 0
CalcLoop:
For i = 1 To Len(myNumber)
If IsNumeric(Mid(myNumber, i, 1)) Then temp = temp + Mid(myNumber, i, 1)
Next
If Len(temp) > 1 Then
myNumber = temp
temp = 0
GoTo CalcLoop
End If
SumToOneDigit = temp
End Function
UDF (User Defined Functions) are codes in VBA (visual basic for applications).
When you can not make calculations with Given Excel functions like ones in your question, you can UDFs in VBA module in Excel. See this link for UDF .. If you dont have developer tab see this link ,, Add a module in VBA in by right clicking on the workbook and paste the above code in that module. Remember, this code remains in this workbook only. So, if you want to use this UDF in some other file your will have to add module in that file and paste the code in there as well. If you are frequently using such an UDF, better to make add-in out of it like this link
In addition to using "Text to Columns" as a one-off conversion, this is relatively easy to do in VBA, by creating a user function that accepts the data as a string, splits it into an array separated by spaces, and then loops the elements to add them up.
Add the following VBA code to a new module:
Function fSumData(strData As String) As Double
On Error GoTo E_Handle
Dim aData() As String
Dim lngLoop1 As Long
aData = Split(strData, " ")
For lngLoop1 = LBound(aData) To UBound(aData)
fSumData = fSumData + CDbl(aData(lngLoop1))
Next lngLoop1
fExit:
On Error Resume Next
Exit Function
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "fSumData", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume fExit
End Function
Then enter this into a cell in the Excel worksheet:
=fSumData(A1)
Regards,
The UDF below will return the sum of all numbers in a cell passed to it as an argument.
Function SumCell(Cell As Range) As Double
Dim Fun As Double ' function return value
Dim Sp() As String ' helper array
Dim i As Integer ' index to helper array
Sp = Split(Cell.Cells(1).Value)
For i = 0 To UBound(Sp)
Fun = Fun + Val(Sp(i))
Next i
SumCell = Fun
End Function
Install the function in a standard code module, created with a name like Module1. Call it from the worksheet with syntax like =SumCell(A2) where A2 is the cell that contains the numbers to be summed up. Copy down as you would a built-in function.

Extracting a substring from a cell at a certain index (different row length, multiple rows)

Working as an accountant, and I'm wondering if there's a way to extract a certain string of characters, at a certain index, from a cell of varying lengths. Sometimes, I receive a statement of account as a PDF, which doesn't convert nicely to an Excel spreadsheet.
This is what I want to achieve
The strings are at the same index within each cell. I can't quite figure out how to isolate them, though, because each string is a different length, and the substring I want doesn't start with the same character. I've tried LEN, MID, etc. to extract them, but I'm not sure how to do it.
I was able to extract items that start with specific characters (like INV and "45") with:
=TRIM(MID(SUBSTITUTE(A1," ",REPT(" ",99)),MAX(1,FIND("XXX",SUBSTITUTE(A1," ",REPT(" ",99)))-50),99))
But I can't figure out how to get the strings I'm looking for (in this case, the amounts for the invoices).
If you don't mind some VBA, you can try this:
The basic problem with the data is the dates included in the fields are variable length and include the only real delimiter (spaces) within those elements. Using the spaces from the right, can be used to return your fields.
Credit to Sumit Bansal at (https://trumpexcel.com) for the original LastPosition() function. However, this function only returns the last occurrence of a character.
But a couple of slight modifications, LastPositionN() now returns the nth occurrence of the search text, to be specified as a 3rd parameter.
Note: Follow here for the original function, and info on cutting/pasting into the VBA editor: https://trumpexcel.com/find-characters-last-position/
Function LastPosition(rCell As Range, rChar As String)
'This function gives the last nth position of the specified character
'This code has been developed by Sumit Bansal (https://trumpexcel.com)
Dim rLen As Integer
rLen = Len(rCell)
For i = rLen To 1 Step -1
If Mid(rCell, i - 1, 1) = rChar Then
'LastPosition = i ' original code returnd Last position +1
LastPosition = i - 1 ' correction returns codes original intent
Exit Function
End If
Next i
End Function
Function LastPositionN(rCell As Range, rChar As String, Optional nNthOccurance As Integer = 1)
'This function gives the last position of the specified character
'This code has been developed by Sumit Bansal
' (https://trumpexcel.com)
' and was modified my Jeff Bowman 9/11/2018 for nth position from right
'Returns zero (0) if not nth occurence is not found
Dim rLen As Integer, nNthCount As Integer, LastPosition As Integer
nNthCount = 0
rLen = Len(rCell)
For i = rLen To 1 Step -1
If Mid(rCell, i - 1, 1) = rChar Then
'LastPosition = i ' original code returnd Last position +1
LastPositionN = i - 1 ' correction returns codes original
'intent
nNthCount = nNthCount + 1
If nNthCount = nNthOccurance Then
Exit Function
End If
End If
Next i
End Function
`
Now, with left(), right(), and find() we can isolate and parse the end of the data string.
=LEFT(RIGHT(A8,LastPositionN(A8," ",1)),FIND(" ",RIGHT(A8,LastPositionN(A8," ",1))))

Summing cells that have formula and string concatenated together

I have a column with formula as follows:
=(2+3*6+8) & "KB"
Basically, each cell is a formula and string concatenated (using &). I want to add all these cells up. I tried the following things:
a) =SUM(B2:B21) gives me a sum of 0.
b) Using =B2+B3... gives me a #VALUE error.
c) I tried something like this also - didn't work, gives a sum of 0: =SUM(IF(ISNUMBER(FIND("KB",$C$2:$C$14)),VALUE(LEFT($C$2:$C$14,FIND("KB",$C$2:$C$14)-1)),0))
Make your own SUM function in VBA. Try this:
=StripTextAndSum(A2:A4) - returns 60
=StripTextAndAverage(A2:A4) - returns 20
This method keeps the left most decimal number and tosses away the rest.
NOTE: You can tweak this to fit your needs. One way would be to retain the text so you can return it in the sum....like 150MB (i am assuming KB means kilobyte). Let me know if you like that idea and I'll make it.
EDIT: As pointed out by #DirkReichel, this has been made a little more efficient using IsNumeric instead, but I have retained all the other functions too. IsLetter is a useful function too.
Public Function StripTextAndSum(myRange As Range)
Dim r As Range
Dim n As Double
n = 0
For Each r In myRange.Cells
n = n + ParseNumberFromString(r.Text)
Next r
StripTextAndSum = n
End Function
Public Function StripTextAndAverage(myRange As Range)
Dim n As Double
n = StripTextAndSum(myRange)
StripTextAndAverage = n / (myRange.Cells.Count * 1#)
End Function
Public Function ParseNumberFromString(s As String) As Double
ParseNumberFromString = Left(s, GetLastNumberIndex(s))
End Function
Public Function GetFirstLetterIndex(s As String) As Integer
Dim i As Integer
For i = 1 To Len(s) Step 1
If IsLetter(Mid(s, i, 1)) = True Then
GetFirstLetterIndex = i
Exit Function
End If
Next i
End Function
Public Function GetLastNumberIndex(s As String) As Integer
Dim i As Integer
For i = Len(s) To 1 Step -1
If IsNumeric(Left(s, i)) = True Then
GetLastNumberIndex = i
Exit Function
End If
Next i
End Function
Function IsLetter(s As String) As Boolean
Dim i As Integer
For i = 1 To Len(s)
If LCase(Mid(s, i, 1)) <> UCase(Mid(s, i, 1)) = True Then
IsLetter = True
Else
IsLetter = False
Exit For
End If
Next
End Function
I'd normally just move the KB to the following column and left-justify it.
That way, it still looks identical but the first column only has real numbers that you can manipulate mathematically to your heart's content.
Or, assuming they're all in kilobytes (which seems to be a requirement if you just want to add the numeric bits), don't put KB in the data area at all.
Instead change the heading from, for example, Used memory to Used memory (KB).
Do you really want to populate your beautiful spreadsheets with butt-ugly monstrosities like the following? :-)
=SUM(IF(ISNUMBER(FIND("KB",$C$2:$C$14)),VALUE(LEFT($C$2:$C$1‌​4,FIND("KB",$C$2:$C$‌​14)-1)),0))
If you need to keep your column as-is, you could always use an array formula to get the sum:
=sum(value(left(b2:b21,len(b2:b21)-2)))
You will need to enter this as an array formula (press Ctrl+Shift+Enter to submit it)
Basically this is taking the leftmost chunk of a cell (all but the last two characters, which we know are 'KB'), using value() to convert it into a numeric, and sum() to add it up. Entering it as an array formula just lets us do this to each cell in the list b2:b21 in one swoop.
As #paxdiablo mentioned, though, it might be best to restructure so that you don't have to deal with your values as text in the first place. My approach would be to enter the values and add the "KB" via formatting. You can use a custom formatting with something like 0.00 "KB" so the cell only holds, say, the value 17, but it displays as "17.00 KB".

Reversing domain text in excel formula (split, reverse array, join)

Say I have a field in excel with a domain name and I would like to reverse the order of the subdomains, domain and tld, for sorting purposes. For example:
"my.sub.domain.example.org" becomes "org.example.domain.sub.my"
How would you do that in excel?
I'm not sure how you would do it with worksheet functions, creating a function to do it for you is a lot easier.
If you open the VBA editor, insert a new module and paste the following function you can use it on your worksheet.
Public Function Reverse(ByVal Expression As String, ByVal Delimiter As String) As String
Dim Data() As String
Dim Result As String
Dim Index As Integer
Result = ""
Data = Split(Expression, Delimiter)
Index = UBound(Data)
Result = Data(Index)
Do
Index = Index - 1
Result = Result & Delimiter & Data(Index)
Loop While Index > 0
Reverse = Result
End Function
Example
A1 ="my.example.site.tld"
A2 ="=Reverse(A1,".")"
A2=="tld.site.example.my"
Use text to columns with a period delimiter. then you can splice them together using =concatenate(...) or & (concatenation operand) in the order and format that you desire.
(but the VBA answer NickSlash posted is nice, this is just in case you want non-VBA)

Resources