I have an Excel macro that formats a sheet down to its relevant data.
One of the columns I have taken (column C) has full names of individuals - and I am trying to put in a calculation that will pare the full name down to initials.
I have a calculation that works, if used by itself...but when I put it into the VBA macro, I get the "Expected: End of Statement".
The formula itself is:
=LEFT(C2)&IF(ISNUMBER(FIND(" ",C2)),MID(C2,FIND(" ",C2)+1,1),"")&IF(ISNUMBER(FIND(" ",C2,FIND(" ",C2)+1)),MID(C2,FIND(" ",C2,FIND(" ",C2)+1)+1,1),"")
The VBA code I have is:
Enter_Formulas() = "=LEFT(C2)&IF(ISNUMBER(FIND(" ",C2)),MID(C2,FIND(" ",C2)+1,1),"")&IF(ISNUMBER(FIND(" ",C2,FIND(" ",C2)+1)),MID(C2,FIND(" ",C2,FIND(" ",C2)+1)+1,1),"")"
I get the End of Statement error at the first FIND part above, I believe because the ", followed by a space seems to signal the end of the statement - how do I overcome this? Or is there a better way to achieve what I am trying?
Related
I am quite new to VBA but have been working with Excel a bit. I created a formula that does exactly what I need it to do: find the Nth to last word (mostly 2nd or 3rd to last) in a cell. I think my main issue is how to apply a formula to a range of cells without overwriting the cell and how to use excel formulas in VBA. The Excel formula I use is as follows
=TRIM(LEFT(RIGHT(" "&SUBSTITUTE(TRIM(A1)," ",REPT(" ",60)),180),60))
It might not be the most eloquent way but it works pretty well in Excel. Changing the number 180 to 60 will give last word, 120 2nd to last and so on. But in VBA it gives 1st syntax error and when I get it to run without the arguments and with only TRIM(A1) it overwrites the cell. The code I use is as follows (referencing only A1 to test it):
reportsheet.Range("A1").Formula = "=TRIM(LEFT(RIGHT(" " & SUBSTITUTE(TRIM(A1)," " ,REPT(" ",60)),180),60))"
My macro searches and extracts specific data from Sheet1 to Sheet2. Now I would want to apply this (or a similar) formula to the data it extracts to the Sheet2. I have tried a lot of different things from using VBA's own trim to making a completely custom function. None of it seems to work and I think it is down to a misunderstanding on how Excel formulas and VBA play together.
In addition I am trying to find a way to find the only numbers in the cell and trim out everything else. Any help with this would also be appreciated.
EDIT: Sorry guys, I had a mistake in the code I provided, it should have been referring to A1 in both instances.
Double up quotes within a quoted string or use alternatives.
reportsheet.Range("A1").Formula = "=TRIM(LEFT(RIGHT("" "" & SUBSTITUTE(TRIM(A20),"" "" ,REPT("" "",60)),180),60))"
'alternative
reportsheet.Range("A1").Formula = "=TRIM(LEFT(RIGHT(char(32) & SUBSTITUTE(TRIM(A20), char(32), REPT(char(32),60)),180),60))"
Doubling the quotes as #Jeeped and the commenters wrote is solving your issue with the formula.
As an alternative, you could write a function ("UDF") that returns the n-th word of a string. It is rather easy by using the VBA function split that returns an array of strings. Put the following code in a Module:
Public Function getWord(s As String, ByVal n As Integer) As String
n = n - 1 ' Because Array index will start at 0
Dim arr() As String
arr = Split(s, " ")
If UBound(arr) >= n Then
getWord = arr(n)
End If
End Function
In Excel, you write for example =getWord(A20, 3) as formula
After several hours of research, I still can't solve what seems to be a pretty simple issue. I'm new to VBA, so I will be as specific as possible in my question.
I'm working with a DDE link to get stock quotes. I have managed to work out most of the table, but I need a VBA to create a finished formula (i.e., without cell referencing) in order to the DDE link to work properly.
My first code is as follows:
Sub Create_Formulas()
Range("J1").Formula = "=Trade|Strike!" & Range("A1").Value
End Sub
Where J2 is the blank cell and A2 contains the stock ticker. It works fine, but when I try to fill out the rows 2 and bellow, it still uses A1 as a static value.
Sub Create_Formulas()
Dim test As Variant
ticker = Range("A1").Value
'Test to make variable change with each row
'Range("J1:J35").Formula = "=Trade|Strike!" & Range("A1:A35").Value
'not working
Range("J1:J35").Formula = "=Trade|Strike!" & ticker
'not working
End Sub
I couldn't find a way to solve that, and now I'm out of search queries to use, so I'm only opening a new topic after running out of ways to sort it by myself. Sorry if it is too simple.
You are referencing absolute cell adresses here. Like you would do when using $A$1 in a normal excel formula.
What you want to do is:
Dim row as Integer
For row = 1 to 35
Cells(row,10).Formula = "=Trade|Strike!" & Cells(row,1).Value
Next row
This will fill the range J1 to J35 with the formula. Since (row,10) indicates the intersection of row and column 10 (J)
Firstly, in your second set of code, you define a variable "test", but never give it a value.
You assign a value to the variable "ticker", and then never reference it.
Secondly, the value you have assigned to ticker is a static value, and will not change when it is entered in a different row.
Thirdly, I think your issue could be solved with a formula in Excel rather than VBA.
The "INDIRECT" function can be quite useful in situations like this.
Try inserting the formula
=INDIRECT("'Trade|Strike'!"&A1)
into cell A1, then copy down.
Note the ' ' marks around "Trade|Strike". This is Excels syntax for referencing other sheets.
I am new to VBA and have had some success reverse engineering VBA using the VBA Recorder. However I am having a problem creating a CountIfs() loop for all cells containing the value "TT" in EITHER an entire column OR a dynamic range of a single column (using .end(xldown) / .end(xlup))
I would post my code but honestly, I have found so many different 'answers' to this question that I have not been able to mold to my use case yet and I do not think I am very close with any individual methodology. (ultimately I need to expand this to be a CountIfS() based on other column values but one step at a time)...
THANKS!!
What about this simple code---
Sub vbaCountIF()
Dim Rslt
Rslt = WorksheetFunction.CountIfs(Range("A:A"), "TT")
MsgBox Rslt
End Sub
I have many uses of the INDIRECT function in my workbook, and it is causing performance issues. I need to replace them with something that will give me the same results. All the INDIRECTS recalculate anytime anything is changed, causing the workbook to lag.
I was wondering if there is a way to code INDIRECT in VBA without actually using the INDIRECT function, and take away the volatility of the function in the code.
=INDIRECT("'" & $AC$9 & "'!" & AC26)
This is an example. I need to remove INDIRECT but get the same results for this cell. Is there a way to accomplish this in VBA?
You can try this.
Place the following routines in a standard code module:
Public Function INDIRECTVBA(ref_text As String)
INDIRECTVBA = Range(ref_text)
End Function
Public Sub FullCalc()
Application.CalculateFull
End Sub
Replace the INDIRECT functions in your formulas with INDIRECTVBA.
These will be static. If the slowness of your workbook is because your INDIRECTs are constantly evaluating, then this will put an end to that.
IMPORTANT: all cells that contain a formula using INDIRECTVBA will be static. Each formula will calculate when you confirm it, but it will not recalculate when precedents change.
You will then need a way to force them to recalculate at a convenient time. You can do that from the Ribbon. Or, you can run FullCalc.
Was going to add this as a comment, but my thought process got too long.
What is the context of the problem you are trying to solve?
I am guessing you are using some kind of data validation drop-down menu in $AC$9 to select a sheet name and then all your INDIRECT formulas are providing a mirror image of a particular section of the user-specified worksheet.
If that is the case then you might consider using INDEX as an alternative. It is written as =INDEX(Range, RowNum, ColNum) E.g. if you put this in H20: =INDEX(Sheet1!A:Z,ROW()+10,COLUMN()-5) then it would reflect whatever is in sheet 1, cell C30 (H - 5 columns, 20 + 10 rows). Of course, you don't have to offset anything if you don't want to, I just wanted to demonstrate that as an option.
Now, the trickier part would still remain - assigning/updating the SheetName variable. This could be done with a UserForm instead of typing in a value in a particular input cell. For example, you could have VBA provide an input box/dropdown menu for the user to select one of the available sheet names, then take that input and use it in a quick find and replace instruction - searching for "=INDEX(*!" and replacing with "=INDEX(" & InputVariable & "!"
I've made a few assumptions about your dataset and what you're trying to achieve, so it might not be the ideal solution, but perhaps something to think about.
The solution to volatility with the Indirect function (typical in multi-version cross platform use and partitioning to run Windows on Mac) can be absorbed by splitting its various functions with a pseudonym for Indirect I have named "Implied":
Public Function Implied(Varient)
' CREDIT: Stephen L. Rush
On Error Resume Next
If IsError(Range(Varient)) Then
If IsError(Find(Varient, "&")) Then
'Not Range, is Indirect. "A" & Match() Style (where Match() = row).
Implied = WorksheetFunction.Indirect(Varient)
Else
'Not a Range, not Indirect. "A" & B99 Reference (where B99 = row).
Implied = Range(Left(Varient, Find(Varient, "&") - 1) & Range(Right(Varient, Len(Varient) - Find(Varient, "&"))))
End If
Else
'Is pure Range
Implied = Range(Varient)
End If
'[On Error GoTo 0] Conflicts with use as formula
End Function
I got the following code
=LEFT(A2, MIN(ROW(INDIRECT("1:"&LEN(A2)))+(((CODE(MID(UPPER(A2),
ROW(INDIRECT("1:"&LEN(A2))), 1))>64)*(CODE(MID(UPPER(A2),
ROW(INDIRECT("1:"&LEN(A2))), 1))<91))+
((CODE(MID(A2, ROW(INDIRECT("1:"&LEN(A2))), 1))>47)*
(CODE(MID(A2, ROW(INDIRECT("1:"&LEN(A2))), 1))<58)))*1E+99)-1)
I have this code and a few others, but how can I make it into a macro applicable to my entire workbook? I know its probably the same as a macro in terms of time, but I eventually want to loop it throughout a directory and would help automate a process. Is there a way to make this a macro for my workbook?
The crudest quickest way would be something like this:
Range("J2:J5000").Formula = "=LEFT(A2, MIN(ROW(INDIRECT(""1:""&LEN(A2)))+(((CODE(MID(UPPER(A2), ROW(INDIRECT(""1:""&LEN(A2))), 1))>64)*(CODE(MID(UPPER(A2), ROW(INDIRECT(""1:""&LEN(A2))), 1))<91))+((CODE(MID(A2, ROW(INDIRECT(""1:""&LEN(A2))), 1))>47)*(CODE(MID(A2, ROW(INDIRECT(""1:""&LEN(A2))), 1))<58)))*1E+99)-1)"
Which will put your exact formula in the range (and update itself according to the row reference). Obviously the reference to column J can be changed and the 5000 can be made dynamic using rows.count).end(xlup).row but without knowing which columns to play with I just had to take a stab at a crude solution.
However depending on what your "symbols" could be a solution using the split command would most likely be the better choice. Can you post more direction on this? Then I can edit this answer and add a code solution in for that for you.
Also include some sample data and expected results, maybe 10 rows worth to give a good set for testing
For an example of how the split command works select one of the cells with data in it that you need to split on the underscore and go to the debug window in the VBE (CTRL-G) and enter this (including the question mark) then press enter.
?split(Activecell.text,"_")(0)
Now update the 0 to 1 and press enter. This will show you how this command works, it splits a string to an array based on the delimiter you give it.
EDIT:
This code will do what you want, Notice how Split is being used.
Function GetFirstPart(SplitString As String)
Dim PosibleSplits As Variant, X As Long
PossibleSplits = Array("_", "+", "-")
For X = LBound(PossibleSplits) To UBound(PossibleSplits)
If Len(SplitString) <> Len(Split(SplitString, PossibleSplits(X))(0)) Then
GetFirstPart = Split(SplitString, PossibleSplits(X))(0)
Exit For
End If
Next
End Function
Use it by pasting the code into a module then in your sheet use it the same as any other formula =GetFirstPart(A1) where A1 has the string to split, drag down as far as your data goes.
You can add other delimiters in this line PossibleSplits = Array("_", "+", "-")