I need to get the column letters of a range for a macro. I specifically need the column letters, the numbers you get for columns directly using VBA Address functions won't work. Since the ranges are always from one column only, this simplifies the task. The range retrieved could be something like B3 or B3:B5, but always the same column and are inside a table.
So, what I need (in this case) to get would be B as a string. I tried to do the following:
RangeOfInterest = Worksheets("Sheet1").Range("Table1[Column1]").Address(0, 0)
RangeColumn = Right(RangeOfInterest, Len(RangeOfInterest) - InStr(RangeOfInterest, [0-9]))
However, I run into a series of issues with this. First, there is the InStr function. I thought this was the best way, because this function searches for the position of a character starting from the left, which is exactly what I need. However, I would need it to search for many values (any number from 0 to 9). Could I add all the numbers as search arguments or use some kind of trick to search between a range of numbers? What I tried certainly doesn't work.
On the other hand, I assume that if I somehow manage to add all numbers from 0 to 9, the function would start searching for them one by one instead of stopping the first time there is any number in the string? This would result in the issue that if for example there is a range like B3:B10 it will begin searching for a 0 and return the position of the 0 and finish, hence my code will return the string B3:B1 instead of just B.
Also, I can't just use a fixed solution like Left(RangeOfInterest, 1) to get the B because the code should work with any range, and once you reach the Z the column letters are double and go like AA, AB and so on.
I thought that another alternative would be to loop, but all my tries resulted in very complex pieces of code for what seems to have a pretty easy solution. Also, if possible, I would like to avoid looping although that doesn't matter if there is no other option. I would really appreciate any suggestion to solve this.
More often, one wants the number of a columns than its name because if you feed Excel the name it will convert it to the corresponding number for processing. Therefore I hope it isn't that you need the name for the purpose of addressing a cell using VBA. Anyway, here you go:-
Dim RangeOfInterest As String
RangeOfInterest = Worksheets("Sheet2").Range("Table1[Column1]").EntireColumn.Address(0, 0)
RangeOfInterest = Split(RangeOfInterest, ":")(0)
Debug.Print RangeOfInterest
Related
what is the easiest way with an Excel formula to extract certain details from a cell? So for example, if this is in cell A1 column=""HMI_LOCATE"" px=""CLASS"" position=""99"" validation=""ROOM"" then I'm trying to extract just the data the falls in between the double "" after the px= so in this example, I need to extract just the letters CLASS and nothing else, what is the easiest way to extract that data, the part I'm trying to extract won't always be 5 characters long it could be much longer or shorter.
Do you want to achieve this?
With o365 you can use this formula
=FILTERXML("<t><s>"&SUBSTITUTE(A1,CHAR(34)&CHAR(34),"</s><s>")&"</s></t>","//s[position() mod 2 = 0]")
or for older EXCEL-versions
=IFERROR(INDEX(FILTERXML("<t><s>"&SUBSTITUTE($A$1,CHAR(34)&CHAR(34),"</s><s>")&"</s></t>","//s"),ROW(A1)*2),"-")
This splits the string at the quotation marks (CHAR(34)) and builds an array of elements. Then every second element is put out.
For tons of other possibilities have a look at this awesome guide by JvdV.
EDIT:
To get the element after px= no matter where it is, you can use
=LET(list,
FILTERXML("<t><s>"&SUBSTITUTE($A$1,CHAR(34)&CHAR(34),"</s><s>")&"</s></t>","//s"),
INDEX(list,MATCH("px=",list,0)+1)
)
The LET-function lets you assign functions to variables which then can be used for further calculations.
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.
First Question: So I'm sorry if the formatting etc is awful.
I have one very long column of integers and I need to multiply every element by a constant (ex:2) and fill the next column over.
I know how to make it work by looping through each element but I was hoping there was a single command for it.
[D1:D25].Value = [C1:C25*2]
works for me, but it prints 0 where there were null spaces, so I need to define the range more specifically.
How can I define the both ranges in terms of variables and keep the multiplication functioning.
i.e.
.Range(.cells(firstRow, 1),.cells(lrow,1))*2
gives a type mismatch error.
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.
I vaguely remember that it is possible to parse the data in a cell and keep only part of the data after setting up certain conditions. But I can't remember what exact commands to use. Any help/suggestion?
For example, A1 contains the following info
0/1:47,45:92:99:1319,0,1320
Is there a way to pick up, say, 0/1 or 1319,0,1320 and remove the rest unchosen data?
I know I can do text-to-column and set the delimiter, followed by manually removing the "un-needed" data, but my EXCEL spreadsheet contains 100 columns X 500000 rows with each cell looking similar to the data above, so I am afraid EXCEL may crash before finishing the work. (have been trying with LEFT, LEN, RIGHT, MID, but none seems to work the way I had hoped)
Any suggestion will be greatly appreciated.
I think what you are looking for is combination of find and mid, but you'll have to work out exactly how you want to split your string:
A1 = 0/1:47,45:92:99:1319,0,1320 //your number
B1 = Find(“:“,A1) //location of first ":" symbol
C1 = LEN(A1) - B1 //character count to copy ( possibly requires +1 or -1 after B1.
=Left(A1,B1) //left of your symbol
=Mid(A1,B1+1,C1) //right size from your symbol (you can also replace C1 with better defined number to extract only 1 portion
//You can also nest the statements to save space, but usually at cost of processing quantity increase
This is the concept, you will probably need to do it in multiple cells to split a string as long as yours. For multiple splits you probably want to replicate this command to target the result of previous right/mid command.
That way, you will get cell result sequence like:
0/1:47,45:92:99:1319,0,1320; 47,45:92:99:1319,0,1320; 92:99:1319,0,1320; 99:1319,0,1320......
From each of those you can retrieve left side of the string up to ":" to get each portion of a string.
If you are working with a large table you probably want to look into VB scripting. To my knowledge there is no single excel command that can take 1 cell and split it into multiple ones.
Let me try to help you about this, I am not a professional so you may face some problems. First of all my solution contains 2 columns to be added to the source column as you can see below. However you can improve formulas with this principle.
Column B Formula:
=LEFT(A2,FIND(":",A2,1)-1)
Column C Formula:
=RIGHT(A2,LEN(A2)-FIND("|",SUBSTITUTE(A2,":","|",LEN(A2)-LEN(SUBSTITUTE(A2,":","")))))
Given you statement of having 100x columns I imagine in some instances you are needing to isolate characters in the middle of your string, thus Left and Right may not always work. However, where possible use them where you can.
Assuming your string is in cell F2: 0/1:47,45:92:99:1319,0,1320
=LEFT(F2,3)
This returns 0/1 which are the first 3 characters in the string counting from the left. Likewise, Right functions similarly:
=RIGHT(F2,4)
This returns 1320, returning the 4 characters starting from the right.
You can use a combination of Mid and Find to dynamically find characters or strings based off of defined characters. Here are a few examples of ways to dynamically isloate values in your string. Keep in mind the key to these examples is the nested Find formula, where the inner most Find is the first character to start at in the string.
1) Return 2 characters after the second : character
In cell F2 I need to isolate the "92":
=MID(F2,FIND(":",F2,FIND(":",F2)+1)+1,2)
The inner most Find locates the first : in the string (4 characters in). We add the +1 to move to the 5th character (moving beyond the first : so the second Find will not see it) and move to the next Find which starts looking for : again from that character. This second Find returns 10, as the second : is the 10th character in the string. The Mid formula takes over here. The formula is saying, Starting at the 10th character return the following 2 characters. Returning two characters is dictated by the 2 at the end of the formula (the last part of the Mid formula).
2) In this case I need to find the 2 characters after the 3rd : in the string. In this case "99":
=MID(F2,FIND(":",F2,FIND(":",F2,FIND(":",F2)+1)+1)+1,2)
You can see we have simply added one more nested Find to the formula in example 1.