I want to count the number of numbers in a single cell.
Example:
In cell A1, I have the following addition:
=12+45+23+51+10 which totals (and shows) 141.
In cell B1, I would like the see how many numbers have been added together, which means that there should be 5 (12 is a number, 45 another one, etc... and all together, there are 5 numbers in cell A1).
I know it seems to be a ridiculous question, but I scanned all the platforms for this issue and did not find any suitable solution. Tried all the LEN and LEN SUBSTITUTE alternatives out there, but somehow it does not work.
Thank you upfront for your help. Optimal solution would be a excel formula, alternatively VBA would also work.
Excel 2013 has a new function Formulatext() which returns the, well, formula text. Using that the Len() and Substitute() approach works.
=LEN(FORMULATEXT(A1))-LEN(SUBSTITUTE(FORMULATEXT(A1),"+",""))+1
Hit Alt+F11 and Insert->Module with the following VBA:
Function NumCount(Rng As Range)
x = Split(Rng.Formula, "+")
NumCount = UBound(x) + 1
End Function
Then you can call =NumCount(A1) on any cell to get the number of numbers in the formula for that cell.
Use this VBA:
Function GetFormula(Cell as Range) as String
GetFormula = Cell.Formula
End Function
and then to get the number of numbers...
=LEN(GetFormula(D99))-LEN(SUBSTITUTE(GetFormula(D99),"+",""))
on this as my D99 contents...
=45+46+47+50+100
The one major drawback here is that I'm assuming everything is + if you have -, *,/ or other operators this gets more challenging. you might be able to use replace for each but you'd always be limited to the 4 basic operators... if someone used exponents or mod, this would be harder.
Also possible in earlier Excel versions without VBA - subject to (i) there is always at least one value in the cells, (ii) the operator is always + and (iii) the cells are in a column.
Replace = with '= in that column, apply the substitution, say:
=LEN(A1)-LEN(SUBSTITUTE(A1,"+",""))+1
in a different column and Paste Special, Value the results for that other column. Then apply Text To Columns on the original column with ' as the delimiter.
*There is no way to do this without using a User Defined Function (UDF) written in Excel VBA. Something like this should work:
Public Function numsAdded(cell1 As Range)
Dim formulaString As String
formulaString = cell1.Formula
numsAdded = Len(formulaString) - Len(Replace(formulaString, "+", "")) + 1
End Function
Once you've added that to a VBA module, you can use it as a function in any cell in your spreadsheet.
*Edit - Apparently there is a way if you have Excel 2013, as teylyn suggests. If you use 2010 or earlier like me, you'll need VBA.
Try this:
=LEN(SUBSTITUTE(F16,"+","+"))
Note: F16 is only an example name for the cell you want to do the counting on.
Example:
F16=45+65+76 # Gives 186
F17=LEN(SUBSTITUTE(F16,"+","+")) # Gives 3
Related
I would like to put the below coding into a vba like a function. There is a bunch of data created already by VBA, and when the VBA does its work, then the following function should be run, but i dont know how to add to my vba so that the function always runs as long as data contains. The macro i created already puts the datasheet together, now instead of creating the below with lenthy codings, i just want my macro to run the below, like a man who clicks on the below right hand corner of the cell which contains the below function.
It should be something: Activesheet.ForulaR1C1 = "=RIGHT(AY4,LEN(AY4)-FIND(".",AY4))" something. Can someone help me? Thanks
ORIGINAL FUNCTION TO BE RUN "=RIGHT(AY4,LEN(AY4)-FIND(".",AY4))"
This is where I am at now:
Sub Project_numbers()
Dim j As Integer
Zorro = Range("AY" & Rows.Count).End(xlUp).Row
o = 4
Worksheets("MJE").Range("AF" & o).FormulaR1C1 = "=RIGHT(AE4,LEN(AE4)-FIND(".",AE4))"
o = o + 1
End Sub
You have a couple of problems here. The biggest is that you've got quotation marks in your formula. VBA reads these as the end of the string, so it's interpreting your formula as two separate text strings: =Right(AE4,LEN(AE4)-FIND( and ,AE4)), separated by a .. This isn't a structure VBA can do anything with, so it's going to fail at that point.
When you're inserting a formula with VBA that contains quotation marks, you need to use two quotes together to indicate that it's a literal quote mark that's part of the string, rather than the end of the string:
"=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
The second problem is that you're using the FormulaR1C1 method, which expects cell references to be given in R1C1 (row#column#) notation, rather than A1 notation, but then passing it a formula that uses A1 notation. Again, this is going to confuse the issue and produce errors.
I'm guessing you used the macro recorder to get the syntax, then inserted your own formula? The macro recorder, for some weird reason, loves to use the R1C1 reference style, but we can use a different method for written code.
The full line you need is:
Worksheets("MJE").Range("AF" & o).Formula = "=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
EDITED TO ADD:
With further information, specifically that you need the range referenced to change as you loop, you have some options on how to do it.
1. Use the R1C1 reference style
This allows you to include relative references in formulae easily. You'll use R to designate the formula's row, and C to designate its column; so a cell that referred to itself would simply be =RC. You can follow the R and C with numbers to designate specific rows and columns, so cell B2 would be =R2C2 - row 2, column 2. More usefully, you can use =R[#]C[#] to offset your formula by a certain amount.
In your formula, assuming it's always going to be looking at column AE but whichever row the formula is entered into, your line would be:
Worksheets("MJE").Range("AF" & o).FormulaR1C1 = "=RIGHT(RC31,LEN(RC31)-Find(""."",RC31))"
2. Build your formula from variables.
You already have a variable you can use, o, so we can combine that with the rest of the string to get the appropriate references. It's harder to read, though...
Worksheets("MJE").Range("AF" & o).Formula = "=RIGHT(AE" & o & ",LEN(AE" & o & ") - FIND(""."",AE" & o & "))"
Personally, I find this method rather cumbersome to work with, but it's an option.
3. Assign the formula to your entire range as a single operation
Personally, I prefer this option; I find it to be the neatest one. I'm assuming, from your formula, that your data starts on row 4, and you want the formula to go into every cell between AE4 and the end of your data, which is stored in Zorro. You can use this line to add the formula in one go:
Worksheets("MJE").Range("AF4","AF" & Zorro).Formula = "=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
The cell references will update automatically for each row. There's no need for a loop with this method - of course, if you're looping anyway, that may be no great saving.
I'm trying to set a macro, that will compare multiple lists, create a cross-table with unique values and display how many times the value is present in each list.
I'm doing OK, with one exception. When using Countif(s) formula =COUNTIFS(Source!$A$2:$A$5;[#Values]), it internaly converts "Text numbers" (e.g. 001, 00000002) into Numbers (e.g. 1, 2). I would like to avoid this behaviour and search for EXACTLY the same value, without converting.
Example data:
List1 List2
1 0001
0001
2
00000002
What I'm getting right now (WRONG):
What I want to get (EXPECTED):
My question:
How can I count EXACTLY the values in the list, without internaly converting "Text numbers" to Numbers?
This array formula could be suitable for you:
=MIN(SUMPRODUCT(IF(LEN($A$2:$A$5)=LEN(Table1[#Values]),1,0)),SUMPRODUCT(IF($A$2:$A$5=Table1[#Values],1,0)))
Put and CTRL+SHIFT+ENTER. In Table1[#Values], Table1 is your table name.
I solved the problem with simple UDF.
Function countifsExact(criteria_range As Range, criteria As String) As Long
Dim cell As Range
For Each cell In criteria_range
If cell = criteria Then
countifsExact = countifsExact + 1
End If
Next cell
End Function
EDIT1:
I made another version of the UDF using some of the advice given in Writing efficient VBA UDFs (Part 1) by Charles Williams and in Writing efficient VBA UDFs (Part 2) by Charles Williams.
Mainly:
Storing the criteria_range once in a Variant variable avoiding a large overhead each time a VBA program transfers data from an Excel cell to a VBA variable
Using Range.Value2 property, instead of Range.Value
Using excel MATCH function to get a starting point in the sorted range, with exit on value change.
EDIT2:
Yet a much better solution is to use the SUMPRODUCT formula as such:
=SUMPRODUCT(--(EXACT(Source!$A$2:$A$5;[#Values])))
This seemingly trivial operation can be useful in a number of situations within formulas:
A. functions that would otherwise throw an error:
QUOTIENT(+A1:A3,4)
WORKDAY(+A1:A3,7)
B. converting a range to numbers - i.e. any text to zero:
N(+A1:C3)
C. returning an array of mixed data from different sheets:
CELL("contents",IF(1,+INDIRECT({"Sheet1!A1","Sheet2!B2","Sheet3!C3"})))
I have found very little on this - perhaps this is a new finding.
This question is in part for interests' sake and in part to see if anyone can shed further light or find other possible applications - excel or vba related?
In some of those examples, e.g. for WORKDAY and QUOTIENT, the + is converting a range to an array
Many of the old Analysis ToolPak functions like WORKDAY, NETWORKDAYS, WEEKNUM etc. won't accept a range as an argument, but in Excel 2007 or later excel versions they will accept an array as an argument - using +0 or -- (or apparently +) will convert the range to an array, so in Excel 2007 if you use a formula like this:
=AVERAGE(WEEKNUM(A1:A3))
where A1:A3 contain dates
....it will return an error
but this version (array entered with CTRL+SHIFT+ENTER) will work to give you the average of the week numbers:
=AVERAGE(WEEKNUM(+A1:A3))
Various tests confirm the range to array explanation put forward by Barry Houdini. I'm including some results from the VBE watch window here for reference:
The watch window returns valuable details of the data types returned which are not available in the normal formula evaluation window. Note that [+A1:A3] returns a variant array whereas [A1:A3] returns a range reference. This method also shows that OFFSET and INDIRECT with array argument return arrays of range references. To force array evaluation you can wrap the formula in TRANSPOSE.
As a general technique copy the formula to the immediate window and enclose in square brackets then select the formula in the immediate window and drag to the watch window. No separate code is generally required for this but the VBA Evaluate method (or [] shortcut) doesn't like CELL or INDIRECT. A workaround for examining such formulas is to use the code below pasted into a new module:
Dim v
Function eval(formula As String)
v = Empty
With Application
.Goto "SetV(" & .ConvertFormula(formula, xlA1, xlR1C1) & ")"
End With
eval = v
End Function
Public Function SetV(Value) As Range
v = Value
Set SetV = Selection
End Function
Interesting question. It is clearly some sort of behind the scenes type conversion. I haven't tested your example in C, but it is interesting to note that in the first two cases the unary + can be replaced by either + 0 or Value():
QUOTIENT(A1:A3 + 0,4)
WORKDAY(A1:A3 + 0,7)
N(A1:C3 + 0)
or
QUOTIENT(Value(A1:A3),4)
WORKDAY(Value(A1:A3),7)
N(Value(A1:C3))
As to why exactly this happens -- I don't know. Some functions seem to pass their arguments to Excel as strings when you use them in an array formula and adding 0 (which is what the unary plus does) coerces them to numbers. In VBA I don't think that this trick should be used since it would lead to obscure code, but it is useful to know for array formulas.
I've pasted some numbers on Excel spreadsheet and wanted to do some calculations with it. The problem is that Excel isn't recognizing the numbers. I've already tried several methods to convert them into numbers and none of them works: paste/special multiplying by 1; formating each cell to the number/scientific number format. And there isn't also an error message on the top right corner of each cell like I've read on the internet indicating that there is a number written as text. If I retype each number, Excel recognizes it.
To make sure that the problem was really that the numbers were understood by Excel as text, I tried the functions ISNUMBER(), that returned FALSE and ISTEXT() that returned true.
I want to know how I can fix that problem without having to type into each cell.
Ps. the numbers are in scientific number format, i.e., 1,085859E+001
Since the column is text the cells are formatted as text.
you use Value to convert the text into a number so the formula will work
A2 = 123
A3 = 123 Richard
Formula
=isnumber(A2) result is false
use
=isnumber(value(A2)) result is True
I was having the same problem, until I realized that the decimal separator was set as (,) instead of (.) in the default settings. Once I changed that, everything worked fine.
If your "numbers" are being detected as text, you can use VALUE() to make sure Excel understands that it is actually a number.
A1: `1.23E+10 (this is a string)
B1: =VALUE(A1)
=12300000000
C1: 1.23E+10 (this is a number)
D1: =IF(B1==C1,"It worked", "Uh Oh")
=It Worked (for me anyway)
I'm not sure what the comma in your scientific number will do so might want to have the function replace them if there not required.
See Kenneth Hobs' answer here: http://www.vbaexpress.com/forum/showthread.php?42119-Solved-Convert-exponential-format-to-a-number
Open your Excel File, Press Alt + f11 to open the VBA screen,
Go to Insert > Module, Copy and Paste Kenneth's code:
Sub Expo()
Dim cell As Range, s() As String, lng As Long, n As Integer
For Each cell In Selection
With cell
If Not VarType(.Value2) = vbString Then GoTo NextCell
s() = Split(cell.Value2, "E")
.Value2 = s(0) * 1 * (1 * 10 ^ s(1)) 'ePart(s(1))
.NumberFormat = "General"
.EntireColumn.AutoFit
End With
NextCell:
Next cell
End Sub
You can now run it as a macro to convert selected cells. Or if you want it as a function copy this code instead:
Function Expo(cell As Range)
Dim s() As String
With cell
If VarType(.Value2) = vbString Then
s() = Split(.Value2, "E")
Expo = s(0) * 1 * (1 * 10 ^ s(1)) 'ePart(s(1))
End If
End With
End Function
This way you can use it as a normal function in excel eg =Expo(A1)
As I mentioned in the comments above though, you will have already lost some degree of accuracy when the original number was converted to scientific notation. The best solution is to get the originating program to write the proper numbers into the text file if you can.
Open a new word document and try Pasting the web content in word first, the copy this content from the word document and paste special in excel, as text. This simple solution worked for me
Open a new blank Excel, then go to Data > From Text, this way you can import text and designate which format you want to convert to. On the Text Import Wizard page, select either Delimited or Fixed width (I am not sure how your original text file look like but generally it should be Delimited. On the next page, pick a Delimiter or enter one in Others. On step 3, you should see the data listed below and the data format on the upper left. Pick General for those columns that you believe should not be Text. This should fix your problem.
My case was stubborn, no response to Paste Special or CLEAN(). Finally resolved by copying the offending column of Excel data and pasting into new Notepad++ doc. This revealed a leading "?" in all the bad numbers (apparently some non-printing character). Used Search > Replace to find all "?" and replace with nothing. Edit > Select All, copy to a new Excel column, and voilà!
There may be hidden characters. Trailing/leading spaces may not visible and hence erroneously be neglected. If there is trailing/leading Space characters with numeric values, excel consider it as text.
Copy contents problematic cells to MS-Word [(Select problematic cells and copy them to MS-Word)] and check any hidden characters, Remove hidden characters with "find"/"replace" functionality.
I was having issues with numbers from PPT (e.g. ($3,000))pasted to excel. Tried multiple different ways to get the text to recognize including find replacing parens, commas, $ signs to blank and trying to format so excel could run formulas. The only option that worked was to paste to Word first then paste value to excel which worked without any additional formatting steps. Surprised I could not do it all within excel though. Maybe there's another way
Select all the cells to convert to a number.
|Data| Menu Tab > Data Tools > [Text to columns]
Delimited. [Next]
Deselect all "Delimiters". [Next]
"Column data format" > General
[Finish]
Verify by using =ISNUMBER(C16) in an spare cell, where C16 is a sample cell. Should now return TRUE.
This happened to me lately. I had forgotten that I had set formula recalculation to manual. The weird thing is that it was returing FALSE when initially created (which was correct) but given the test depended on the value of other cells that, when changed, did not trigger the change in the cell with the isnumber() formula.
Pressing F9 "fixed" my problem (and my ignorance).
I'm trying to set a formula for a cell in Excel but I have a strange problem. With the line:
Range("BG4").Formula = "=CustomSum(BG:BG)"
it works fine and the correct formula is set into the cell. But I have another line of code:
Range("BH4").Formula =
"=if(R1C1<>"""","""",if(CustomSum(BH:BH)=0,""geplant!"",CustomSum(BH:BH)))"
This line produces a formula in the cell which looks like this:
=IF($A$1<>"";"";IF(CustomSum(BH:(BH))=0;"geplant!";CustomSum(BH:(BH))))
which is unacceptable since it doesn't work (parentheses in parameter are inserted automatically).
How do I avoid that?
CustomSum looks as follows:
Public Function CustomSum(rng As Range)
Dim Sum As Double
Sum = 0
For row = 10 To 48 Step 2
If IsNumeric(Cells(row, rng.Column).Value) Then
Sum = Sum + Cells(row, rng.Column).Value
End If
Next
CustomSum = Sum
End Function
For the sake of an answer, copied from a Comment by #simoco:
"=if(R1C1<>"""","""",if(CustomSum(BH:BH)
... you can't mix R1C1 and normal formulas
I had the same issue, and found a response here: Absolute referencing - Inserting the equivalent of '$' in an equation written in R1C1 notation.
Long story short, since you have R1C1 at the beginning of your formula, the BH:BH needs to be in R1C1 coordinates as well. BH is column 60. I'm not sure how to specify a whole column as you would in BH:BH, but if your total rows will always be under some large number (500? 6000? depending on your data), you could specify a large range and hopefully have it work fine.
If you have a title for your column, and your data starts row 2, I would write it like this:
Range("BH4").Formula =
"=if(R1C1<>"""","""",if(CustomSum(R2C60:R6000C60)=0,""geplant!"",CustomSum(R2C60:R6000C60)))"