I am trying to reverse-engineer a somewhat complex Excel file and cannot seem to get past this weird statement:
=+IF(case=2;$AE$43;AG43)
There are two things that I don't understand:
The logical test. What does the "case" refer to in this context? I tried searching the file and web for answer, but couldn't find one. The workbook does not include any macros.
The true-value. The formula is located in the cell AE43, so how can it refer to itself?
I suspect case is a named-range. You can view these on the Formula ribbon through the Name Manager. They can refer to cells, ranges, constants, formulas.
And regarding to the circular (self) referencing - you can set Excel to allow these by doing Iterative calculation - see more here Remove or allow a circular reference...
Looks like there will be a bit of investigation down those paths - so good luck!
Try this:
Dim ReverseEngineer As Double
Dim Constant As String
ReverseEngineer = Range("AE43")
Select Case ReverseEngineer
Case Is >= 90
Constant = "Newton"
Case Is >= 80
Constant = "Einstein"
Case Is >= 70
Constant = "Galileo"
End Select
Related
First post here, so apologies if I break any etiquette. If something is missing please let me know so I can edit my post if needed.
I'm currently working on an Excel macro, which enables me to import an interactive pdf form into excel and read data that was written in the form. Most of the script I have down by finding bits and pieces all over the internet, just one specific problem I wasn't able to solve so far.
I have one text field in my pdf that I need to split in two and save the new values in two separate cells. Not a big problem so far, but the formatting may differ, depending on the entered data, so just cutting it of after e.g. a certain amount of characters won't work. Also the quality of the user input data may not be always the same (e.g. sometimes using a hyphen between both parts of the string, using an underscore or no seperator at all). Unfortunately I can't give that text field in the pdf form a strict formatting rule, as the formatting may differ. I also cannot just make to separate form fields in the pdf file for each part of the string. The ease of use is supposed to be on the pdf user's side, not on mine...
Now, what does the data look like:
ABC-1234
ABCD-0123
A1B-12A
As you can see there is not a clear pattern. Please note that as said before the hyphen may not be there or be replaced by an underscore. I added it here to show you the separation of the two sub datasets (lets call them "Data A" for everything on the left side and "Data B" for everything on the right side of the hyphen).
The good thing! I know all the potential values Data A may have. Data B is then just supposed to be stored separately in another cell. My first train of thought was to use InStr, but that may not be the most elegant solution. Data A may be one of around 130 different values, which is also frequently growing. My excel file also has a "helper sheet", in which I store some information for e.g. dropdown menus or deadlines etc. I could store a list of potential Data A candidates here as well.
So what exactly do I need? A method to look at the string, compare it to a list of substrings (Data A, e.g. using a column in my excel sheet as data source) and store that match in Cell A1. Then take that value away from the original string so only Data B remains (I can strip away any hyphens or underscores at this point) and store this value in Cell A2.
Examples:
My import data may look like this: BER1234
Compare this to my list of match candidates, which includes "BER".
Cell A1 = "BER"
Cell A2 = (string minus the match) 1234
Import data: BERA59
Match in my candidate list: BERA
A1 = "BERA"
A2 = "59"
Import data: P9CD-1009A
Match: P9CD
A1 = "P9CD"
A2 = "1009A"
etc.
I may be able to do this with a giant block of if/else and many many InStr comparisons. Problem is, whenever I need to add a new match candidate I will have to go back to coding. It would make my life way easier if I could just e.g. add the value at the bottom of my candidate list and let the macro do it's magic.
I would love to post a piece of code here of what I did so far, unfortunately I really have no idea where to start. I do not expect a ready-to-use piece of code that I can just slab in my macro with copy and paste. If I can't understand the code, I usually go for another solution. Otherwise I can't fix it myself if anything breaks and I don't really like that approach. Giving me pointers on which functions and variable types to look at would be greatly appreciated, though. Maybe I can then piece together what I think it should look like and ask for more help after that step.
My experience level: Kind of beginner, but not total beginner. I have a basic understanding of how things work, but I'm not "fluent" in any programming languages. I know what I want to do and then usually try to get it to work by piecing together different solutions I find on the internet. So far so good, this one's a bit illusive for me, though. Any help is greatly appreciated. As mentioned before, if anything is missing or unclear, I'll gladly try to update this post.
With the suggestions I somewhat got it to work with this:
Dim wb As Workbook: Set wb = ThisWorkbook
Dim LastRow As Long
Dim x As Integer
Dim Remover As String
Dim CatNo As String
Dim Matches As Integer
With Sheets("MenuData")
LastRow = .Range("o" & .Rows.Count).End(xlUp).Row
End With
LastRow = LastRow - 4
Matches = 0
For x = 1 To LastRow
If InStr(AlbumCode1, wb.Sheets("MenuData").Range("O" & x + 4).Value) <> 0 Then
Matches = Matches + 1
Range(ColCatalog & (ImportCell.Row)).Value = wb.Sheets("MenuData").Range("O" & x + 4).Value
Remover = wb.Sheets("MenuData").Range("O" & x + 4).Value
CatNo = Replace(AlbumCode1, Remover, "")
Range(ColCatNo & (ImportCell.Row)).Value = CatNo
End If
Next
MsgBox Matches & (" Matches")
What I do is count the rows and substract 4, because my candidate list starts on row 4. Then do the loop for each x. I have declared all the Colxxx variables as Const at the very beginning of the macro. ImportCell is also declared somewhere else and working as intended for the rest of the data I import. My "Remover" is just set to the value of the match and then gets used to strip it away from the original string that is stored in AlbumCode1 (declared also at the beginning of the macro). Probably not strictly neccessary to do it this way.
So far it works. My candidates may look like this, though:
BER
BERA
If I import data like "BERA12342" I will get two matches (the MsgBox here is for checking what my code does and will be deleted later). As the candidate BERA comes after the candidate BER in my source list it's working fine, because the 2nd "match" just overwrites the first. If they were to be in a different order I would get a false match. Is there a way to only always get one match? Or will I have to make sure the source list is ordered in a certain way?
I suppose you have the candidate list in an Excel file.
If so, you can use a for each loop on the range of your candidate list
To get the full candidate list, even if it grows between two executions, you can use the first cell as a starting point and find the last cell with the toDown() method.
I don't remember its exact name but I've used it before, you can find it by recording a macro and using the Ctrl+Down shortcut.
With these two cells you have the range of your candidate list.
Try to use that formula to check if the cell contains the string:
=IF(IFERROR(FIND("string",A2,1),0)+IFERROR(FIND("string",A2,1),0)>0,"TRUE","FALSE")
source: https://best-excel-tutorial.com/59-tips-and-tricks/600-search-for-string-in-column
Then filter them out and write a for loop to move forward.
I am working on an elongated IF statement that produces different outputs depending on the start of a part number e.g. 3XXXXXXX = Software, 4XXXXXXX = Hardware.
The problem I am having is that the formula outputs FALSE when a part number is yet to be given to the row.
=IF(B2>0,IF(LEFT(D2,1)="1","Assembly",IF(LEFT(D2,1)="2","Sub-Assembly",IF(LEFT(D2,1)="3","Software",IF(LEFT(D2,1)="4","Hardware",IF(LEFT(D2,1)="5","Chemical",IF(LEFT(D2,1)="6","Spare",IF(LEFT(D2,1)="7","Spare",IF(LEFT(D2,1)="8","Document",IF(LEFT(D2,1)="9","Misc",""))))))))))
Please let me know if you can spot where I am going wrong!
You have at least two other options, both of them providing you better maintainable code.
If you use Excel 2016 or higher, there is the SWITCH function. Your formula will then look much more readable:
=IF(B2>0,SWITCH(LEFT(D2,1),"1","Assembly","2","Sub-Assembly","3","Software","4","Hardware","5","Chemical","6","Spare","7","Spare","8","Document","9","Misc",""))
Even in earlier Excel versions, you may use a lookup table, which provides you much higher versatility. Create a table of your categories, you may place them in a separate sheet Categories:
Use VLOOKUP function together with IFERROR to provide the default value when not found:
=IFERROR(VLOOKUP(LEFT(D2,1),Categories!$A$1:$B$9,2,FALSE),"")
You're not putting any value for the first big condition (if B2 is not > 0)
Try this instead:
=IF(B2>0,IF(LEFT(D2,1)="1","Assembly",IF(LEFT(D2,1)="2","Sub-Assembly",IF(LEFT(D2,1)="3","Software",IF(LEFT(D2,1)="4","Hardware",IF(LEFT(D2,1)="5","Chemical",IF(LEFT(D2,1)="6","Spare",IF(LEFT(D2,1)="7","Spare",IF(LEFT(D2,1)="8","Document",IF(LEFT(D2,1)="9","Misc",""))))))))),"")
You can simplify your formula like this:
=IF(B2<=0,"",CHOOSE(LEFT(D2,1),"Assembly","Sub-Assembly","Software","Hardware",
"Chemical","Spare","Spare","Document","Misc"))
I have a ridiculous problem in Excel 2003 where I want to reference a Range I have defined myself, with names such as Div1, Div2, Div3 etc.
I have a macro that determines whether I need to use Div1, Div2, Div3 etc. and I then need to use VLOOKUP and MATCH with these different ranges.
However:
MATCH("ValueSearched", Div1, 0) works fine, but
MATCH("ValueSearched", "Div1", 0) fails
Since Div1 is determined programmatically, it is only stored as a string and I cannot use it.
I understand that in normal programming, you never really reference values like this and would use a hash table or similar, but I thought Excel would have a better work around as everything is done runtime.
Any suggestions on how I can dynamically reference these ranges?
pnuts solved it.
Have you tried =MATCH("ValueSearched",INDIRECT(Div1),0)
If I type the formula 1/4*pi()*($A$1)^2 as a string in a cell and assuming I have a value in $A$1, I use the following VBA function in a third cell to evaluate the formula:
Public Function E(byval TextFormula as String) as Variant
E = Evaluate(TextFormula)
End Function
Is there a way to use math characters like •, √, ¼, π, ², etc. so that my typed-out formula looks more agreeable? Even translate '[' and ']' as '(' and ')'. I can just iterate through an array replacements using REPLACE() function for the simple characters but what about the extended characters like π?
For the really sharp macro'ers...
What about showing intermediate steps (iterations) as in (2*3) + (2.5*4) evaluates to 6 + 10 in the first iteration and then 16 in the next iteration. Asside: I would want the iterations to stop just before each set of addings/subtractings because I sometimes like to know what the relative magnitudes of the individual evaluated terms are to see what part of my formula is controlling the result.
And for the mega-genius ones...
What about mixed units? Such as typing out 560{lbs}/[1.23{m}*3.4{'}] and getting my result in ###{psf} as an example. I thought that the unit could be delineated by the underscore such as 34_kN but I think a start and end delineation is required for compound units like 34{kN/m^2}. There would need to be a way to force the output to a desired unit (ie. mm instead of in) like maybe setting up your desired units ahead in your sheet and then it would at least try to convert to one of those units. I think at this stage you will be charging me for the code;)
I like using Excel for my engineering calculations because I only use simpler formulas (no calculus!) and I don't want to constantly switch between Excel and Mathcad apps but use only one.
Shawn
Those are tall orders. The following sub might give you an idea for your first question:
Sub test()
Dim R As Range
Set R = Range("A1")
R.Value = "A = pr2"
R.Characters(5, 1).Font.Name = "Symbol"
R.Characters(7, 1).Font.Superscript = True
End Sub
Run it an then look at the contents of A1
As far as your second question goes - sure you can do it, but you would need to write a full-fledged expression parser. Writing one from scratch is fairly involved (at least a couple hundred lines of code) and is probably best done by using classes to create a custom tree data type then writing a recursive descent parser to parse strings into expression trees. Doable, though I have neither the time nor the inclination to do so.
I'm not quite sure what you are driving at with your last question, though my gut reaction is that it is easier than your second question since no real parsing is required and it is easy enough to create a dictionary of conversion factors.
Easy enough concept, but I have no idea where to start when it comes to creating a UDF, which is the only thing I can find any mention of. I have a column that populates on source sheets with either a 1 or 2. I want to do something so that all of the "1's" shows as one text entry("AA" for example) and all "2's" show as a different entry(say "BB"). Is this possible without a UDF; and if not then is there any advice on where to start?
You can use custom formatting for this. Right-click the column in question and choose "Format Cells." In the dialog, choose "Custom" and in the box at the top enter:
[=1]"AA";[=2]"BB";General
This assumes that the "1" or "2" is the sole content of the cell. Any other number or text will display in the General format.
This may help you as well. It is a conditional statement that will reference one cell the check if there is content, if not then it will put the word "None" in, otherwise it will put the contents of the cell.
=IF((Sheet1!J1089)="","None",Sheet1!J1089)
Just to update anyone else that may be interested. I have a solution that I am using. Had to go the vba route, but I've got it set up so that my macro for running reports runs the following:
Sub Conversion()
Dim X As Long, DBCodes() As String
DBCodes = Split("AA,BB,CC", ",")
For X = 1 To 3
Columns("H").Replace X, DBCodes(X - 1), xlWhole
Next
End Sub
I can change the split values and the line after for as many more values as I need replacing, though it would take fiddling with to find the point where too many values would make it impractical. Also, it makes a world of difference where I put in the line to run this; found the best spot though and even the reports that are 600+ rows the conversion only adds a couple seconds.