How to find the text between two values in a string? - string

I currently have a cell("Filename"). This returns H:\F0791\Purchase Requisitions\[PCS.xlsm].
I would like to single out the 'F0791' Value. I have previously used MID functions however, this does not work if 'F0791' is a different length.
Would it be possible to call up the values between the first two '\'s or is there a better alternative?
I am seeking this in both formula state and VBA. This is different to other questions because they do not offer a formula alternative.

You could use this UDF, that uses the Split Function
Function EXTRACTELEMENT(Txt As String, n, Separator As String) As String
On Error GoTo ErrHandler:
EXTRACTELEMENT = Split(Application.Trim(Mid(Txt, 2)), Separator)(n - 1)
Exit Function
ErrHandler:
' error handling code
MsgBox "ERROR: Verify if the data exists, example if the separator is correct."
On Error GoTo 0
End Function
And this is a test in VBA
Sub test()
Text = "H:\F0791\Purchase Requisitions[PCS.xlsm]"
Debug.Print EXTRACTELEMENT(CStr(Text), 2, "\")
End Sub
And you could also add it to a Cell, If E1= "H:\F0791\Purchase Requisitions[PCS.xlsm]" Then you add this to the desired result cell.
On cell F1, this formula:=EXTRACTELEMENT(E1;2;"\") gives the result on the image below:
Or open the insert function window
Optional, Description for UDF
This code adds a description for the UDF. You must run it once.
Sub DescribeFunction()
Dim FuncName As String
Dim FuncDesc As String
Dim Category As String
Dim ArgDesc(1 To 3) As String
FuncName = "EXTRACTELEMENT"
FuncDesc = "Returns the nth element of a string that uses a separator character"
Category = 7 'Text category
ArgDesc(1) = "String that contains the elements"
ArgDesc(2) = "Element number to return"
ArgDesc(3) = "Single-character element separator (spc default)"
Application.MacroOptions _
Macro:=FuncName, _
Description:=FuncDesc, _
Category:=Category, _
ArgumentDescriptions:=ArgDesc
End Sub

Another formula approach is to use this formula =MID(A1,4,FIND("----",SUBSTITUTE(A1,"\","----",2),1)-4) in cell B2 in case your strings are in column A

For a formula approach, the following worked for me, given that the "filename" cell is in A1:
=MID(A1,FIND("\",A1)+1,((FIND("\",A1,FIND("\",A1)+1))-(FIND("\",A1))-1))
This basically finds the position of the first "\" and the second "\" and uses the mid() function to pull the string between the two "\"s.

=MID(A2, FIND("\", A2)+1, FIND("\", A2, 4) - 4)
This worked for me assuming that the structure is more or less the same except with regard to the length of the code.

Related

Transpose a split range into a variant array

Morning all, I just tried something and it didn't work.
If I use this function:
Public Function GetPeople()
GetPeople = Application.WorksheetFunction.Transpose(wsPeople.Range("A2:A10").Value2)
End Function
I get a 1D variant / array of 9 strings with the values in cells from A2:A10
I'm trying to do the same for a split range:
Public Function GetPeople2()
GetPeople2 = Application.WorksheetFunction.Transpose(wsPeople.Range("A2,A5,A10").Value2)
End Function
But it only returns the value from A2 and not all three like I wanted.
In reality this split range is defined by a helper column with an "x" - any rows marked "x" will need to be included in this split range.
What is the simplest way to get the same 1D variant array of strings as a function return, but by using a split range?
It's probably just a classic cycling through rows but wondered if .Transpose could still be used.
Office 365 solution (via contiguous range reference)
In reality this split range is defined by a helper column with an "x" - any rows marked "x" will need to be included in this split range.
This allows to pass the entire (contiguous) data column range as function argument evaluating the condition only "x" using the new worksheet function FILTER() with its dynamic Office 365 possibilities.
This allows to get the wanted data directly instead of going the long way round creating a non contiguous range reference first and you can code a one-liner:
Public Function GetPeopleX(rng As Range, _
Optional ByVal criteria = "x", _
Optional ByVal myOffset As Long = 1)
GetPeopleX = Application.Transpose(Evaluate("=Filter(" & rng.Address & "," & rng.Offset(, myOffset).Address & "=""" & criteria & ""","""")"))
End Function
Example call
Sub ExampleCall()
Debug.Print Join(GetPeopleX(Sheet1.Range("A2:A10")), ", ")
End Sub
Addendum
If it's probable that there isn't at least one row marked by x you could add the following error handling to the function GetPeopleX():
On Error Resume Next
Debug.Print UBound(GetPeopleX) ' << force possible error if nothing found
If Err.Number <> 0 Then GetPeopleX = Array(): Err.Clear
As the error handling returns only a declared array without entries (LBound: 0, Ubound: -1), this allows to use Join() for any result, but to check for positive array results in the calling routine via boundaries. So an items count could be done via LBound().
Filter() function
The WorksheetFunction itself building the basis of GetPeopleX() in a simplified form could be
=FILTER(A2:A10,B2:B10="x","")
Syntax: =FILTER(array,include,[if_empty])
c.f. Help Reference Filter function

Any ideas why VBA isn't being case-sensitive in a VLookup?

I've created a VBA Macro to look at a string of input text in the cell E3, split it into individual characters and then VLookup those characters against a table of individual character pixel widths, which is added to the code using a named range, "pw_Table".
The pixel-widths for each letter are then summed and displayed in a cell below the text input box - "Cells(4,5)". Hitting return is meant to show the combined pixel-width total for the complete string.
The problem is that it is not being case sensitive and is using the same VLookup value for both upper and lower case characters.
All the manuals I've seen say VBA is case sensitive on VLookup, and all I can find are ways to get around this.
For my issue, however, the VLookup must be case sensitive to make sure I get the correct pixel width for each letter, for example, "c" is 9 pixels wide, "C" is 13.
I have tried reordering the upper and lower case characters in the table to see if that made a difference, but it only uses the first values it encounters for each letter of the alphabet, whether they be upper- or lower-case.
I thought that I might use INDEX, MATCH, and EXACT, but couldn't see how to implement that in VBA.
This is the Macro code ...
Private Sub ReadCharacter()
cell_value = ThisWorkbook.Sheets("Pixel-widths").Range("E3")
Character_Value = 0
For rep = 1 To Len(cell_value)
Character = Mid(cell_value, rep, 1)
On Error GoTo MyErrorHandler
Character_Value = Application.WorksheetFunction.VLookup(Character, [pw_Table], 2, 0)
Pixel_Width = Pixel_Width + Character_Value
MyErrorHandler:
Character_Value = 10
Resume Next
Next rep
Cells(4, 5) = Pixel_Width
End Sub
I had some issues with numbers, with VBA reporting Run-time Error 1004, but I bodged this by adding an error trap because all the numerals from 0-9 are 10 pixels wide.
I simply can't see why VBA is breaking its own rules.
Vlookup isnt case sensitive.
ive found this function that "simulates" a vlookup case sensitive.
Function CaseVLook(FindValue, TableArray As Range, Optional ColumnID As Integer = 1) As Variant
Dim xCell As Range
Application.Volatile
CaseVLook = "Not Found"
For Each xCell In TableArray.Columns(1).Cells
If xCell = FindValue Then
CaseVLook = xCell.Offset(0, ColumnID - 1)
Exit For
End If
Next
End Function
to use it just call it CaseVLook(F1,A1:C7,3)
more information in here
https://www.extendoffice.com/documents/excel/3449-excel-vlookup-case-sensitive-insensitive.html
good luck
Here's another way...
Character_Value = Evaluate("INDEX(" & Range("pw_Table").Address(, , , True) & _
",MATCH(TRUE,EXACT(INDEX(" & Range("pw_Table").Address(, , , True) & ",0,1),""" & Character & """),0),2)")
Hope this helps!

How do I read the arguments from a formula in VBA?

Say I have the following function:
function MyFunction(A as string, Optional B as integer) as string
to call this function in cell A1:
=MyFunction("Hello","15")
I want to access the arguments of this function from another routine by reading the contents of the cell at A1:
Range("A1").Formula
This however returns the entire formula with arguments as a string as the formula was entered in the cell. Is there a way to easily extract the arguments ("Hello" and 15)?I am trying to avoid the clunky text manipulation route.
If all of your arguments are Ranges, you can use the Precedents property to get at the arguments.
If that's not the case, I'm afraid text manipulation is what you've got. If you're only trying to parse a particular function (instead of any function), it's not that bad.
Function MyFunc(ar1, ar2)
MyFunc = 1
End Function
Public Sub ReadMyFunc(rng As Range)
Dim vaArgs As Variant
vaArgs = Split(Split(Left(rng.Formula, Len(rng.Formula) - 1), "MyFunc(")(1), ",")
Debug.Print "First arg is: " & vaArgs(0) & vbNewLine & "Second arg is: " & vaArgs(1)
End Sub
The result from the immediate window
?activecell.Formula
=MyFunc(A1,"1")
readmyfunc activecell
First arg is: A1
Second arg is: "1"

Not able to split for multiple special characters

I am trying to split cell value up to last "\" in string
'C:\Users\punateng\Desktop\Pending Spec Updates.xlsx' in cell A1 so that result in cell B1 should be 'C:\Users\punateng\Desktop\'
I have written below code:
Sub mu()
Cells(1, 2).Value = Split(Cells(1, 1).Value, "\")
End Sub
But i am getting result as C: in cell B1.
Please help.
This is a case where a function is better than a sub.
Excel has Find and Search functions but doesn't have a FindLast function.
In a User Defined Function (UDF) you can use some functions that aren't available in the Application.WorksheetFunction collection. One of them is InstrRev which finds the position of the first instance of a string like "\" reading backwards from the end of the string. Using This little gem of knowledge and text editing functions you can build this UDF:
Function FileNameFromPath(Path1 As String)
'Test if you have been parsed an network file path
If InStr(1, Path1, "\") > 0 Then
'Get whatever is after the last "\"
FileNameFromPath = Right(Path1, Len(Path1) - InStrRev(Path1, "\"))
Else
'Could be a SharePoint file with http// address
If InStr(1, Path1, "\") > 0 Then
'Get whatever is after the last "/"
FileNameFromPath = Right(Path1, Len(Path1) - InStrRev(Path1, "/"))
Else
'There isn't a path separator there
FileNameFromPath = "That ain't a path"
End If
End If
End Function
So you can call this UDF in any cell in your workbook by typing "=fi", hitting Tab to paste it into your cell, then selecting the cell you want to test and enter a end bracket ")".
Split returns a string array, which in this case will consist of each part of the input text that was previously separated by a \ - so, you are actually returning the array {"C:";"Users";"punateng";"Desktop";"Pending Spec Updates.xlsx"}. When you try to paste this into Cells(1,2), VBA just interprets this as being the first element of the string array.
Instead, you might want to try
Cells(1,2).Value=Left(Cells(1,1).Value,InstrRev(Cells(1,1).Value,"\")-1)
which should find the last instance of \ and return the text before it.

Text Format Macro for Excel

I'm trying to convert a list of names, each in a seperate cell, into a list with # before each name commas afterwards and combined into a single cell. What type of macro would I use for that. So:
Help
Me
Please
Thank
You
into (single cell):
#help, #me, #please, #thank, #you
Thanks
Try this code:
function convertNames(startRow as long,endRow as long,column as long) as string
dim result as string
for c=startRow to endRow
result=result & "#" & Cells(c,column) & ", "
next
result=left(result,len(result)-2)
convertNames=result
end function
You would call this function in the cell where you want to display the results as:
=convertNames(5,12,2)
substituting in the start row, end row, and column index that you need.
Try this function:
Function ConvertNames(List As Range) As String
Dim C As Range
For Each C In List
ConvertNames = ConvertNames & "#" & C.Value2 & ", "
Next C
ConvertNames = Left(ConvertNames, Len(ConvertNames) - 2)
End Function
It is inspired by sigil's answer, but this one works with a range, and allows Excel to manage the references to cells. Sigil's function should be volatile and would slow down large files.
You need to add a module to the project and put this function in the module. Then you can use it by typing =ConvertNames(A1:A5) on the cell that uses it.

Resources