The following code has kicked around with me for many years. I do not know where I picked it up and for the most part it worked, when it worked. However, I have tried to use it on a new document. It worked once then didn't work again. I have tried to add the VB reference to Regular Expressions 5.5 but that was not correct. I was hoping for an easy fix.
The concept of the function was to display the content of a cell as an evaluated equation. It was to "show my work" so to speak so that in complex sheets, checking would be easier.
Unfortunately, the vbscript in the function is a black box to me.
Old Code
Option Explicit
Function SF(r As Range, Z As Integer) As String
Debug.Print r, Z
Const crep As String = "(([A-Za-z0-9_]+|'[^']+')!)?\$?[A-Z]{1,2}\$?[0-9]+"
Const mrep As String = "(([A-Za-z0-9_]+:[A-Za-z0-9_]+|'[^']+:[^']+')\!)|(\$?[A-Z]{1,2}\$?[0-9]+:\$?[A-Z]{1,2}\$?[0-9]+)"
Dim v As Variant, n As Long
Dim regex As Object, matches As Object, m As Object
SF = Mid(r.formula, 2)
Set regex = CreateObject("vbscript.regexp")
regex.Global = True
regex.Pattern = mrep
Set matches = regex.Execute(SF)
If matches.Count > 0 Then Exit Function
regex.Pattern = crep
Set matches = regex.Execute(SF)
n = matches.Count - 1
For n = n To 0 Step -1
Set m = matches.Item(n)
If InStr(m.Value, "!") = 0 Then v = Evaluate("'" & r.Parent.Name & "'!" & m.Value)
If IsNumeric(Val(v)) = True Then
v = Application.WorksheetFunction.Round(v, Z)
End If
SF = Left(SF, m.FirstIndex) & CStr(v) & _
Mid(SF, m.FirstIndex + m.Length + 1)
Next n
SF = "{ =" & SF & "}"
End Function
Updated Code-ish
Function SF(r As Range, Z As Integer) As String
Debug.Print r, Z
Const crep As String = "(([A-Za-z0-9_]+|'[^']+')!)?\$?[A-Z]{1,2}\$?[0-9]+"
Const mrep As String = "(([A-Za-z0-9_]+:[A-Za-z0-9_]+|'[^']+:[^']+')\!)|(\$?[A-Z]{1,2}\$?[0-9]+:\$?[A-Z]{1,2}\$?[0-9]+)"
Dim v As Variant, n As Long
SF = Mid(r.formula, 2)
n = InStr(SF, crep)
While n > 0
If InStr(Mid(SF, n), "!") = 0 Then
v = Evaluate("'" & r.Parent.Name & "'!" & Mid(SF, n, InStr(SF, crep) - n + Len(crep)))
If IsNumeric(Val(v)) = True Then
v = Application.WorksheetFunction.Round(v, Z)
End If
SF = Left(SF, n - 1) & CStr(v) & Mid(SF, n + Len(crep) + 1)
End If
n = InStr(SF, crep)
Wend
SF = "{ =" & SF & "}"
End Function
I can assume that this is not the first time this type of code has been written. Above is an attempt but the cell address is displayed and not the cell value. When referencing a named cell, it just shows the cell name.
Any thoughts? Am I going in the correct direction?
Related
i have a file name the i need to remove some characters below is file name and the goal after trim filename.
My Current String = "text_12_12_19.pdl"
New String Goal = "Text.pdl"
You can use Split:
MyStringGoal = Split(MyCurrentString, "_")(0) & "." & Split(MyCurrentString, ".")(1)
Assuming you are looking to obtain all characters preceding the first underscore, I would suggest the following:
Function TrimFilename(fnm As String) As String
Dim i As Long, j As Long
i = InStr(fnm, "_")
j = InStrRev(fnm, ".")
If 0 < i And i < j Then
TrimFilename = Mid(fnm, 1, i - 1) & Mid(fnm, j)
Else
TrimFilename = fnm
End If
End Function
?TrimFilename("text_12_12_19.pdl")
text.pdl
'Another solution (can also use left and right) :
Dim my_current_string As String
Dim New_String_Goal As String
Dim r As String, l As String
my_current_string = "text_12_12_19.pdl"
l = Left(my_current_string, 4)
r = Right(my_current_string, 4)
New_String_Goal = l & r
Debug.Print New_String_Goal
I have sales report from e-shop and need to calculate cost of goods for each order line. Order line can look like one of these:
2x Lavazza Crema e Aroma 1kg - 1x Lavazza Dolce Caffe Crema 1kg
1x Lavazza Vending Aroma Top 1kg - 1x Arcaffe Roma 1Kg - 1x Kimbo - 100% Arabica Top Flavour
So, what I need Excel to do is to take each product, find its cost with vlookup function from another sheet and then multiply it with amount ordered. The issue is that nr of products ordered can vary from 1 to 10+.
I tried to calculate it with VBA, but the code is not working (I didnĀ“t use multiplying at the moment, I know)
Maybe it is possible to solve this problem with excel formulas?
Function GoodsCost(str, Optional strDelim As String = " ")
larray = Split(str, strDelim)
Set lookup_range = Worksheets("Products").Range("B:E")
For i = LBound(larray) To UBound(larray)
skuarray = Split(larray(i), "x ")
skucost = Application.WorksheetFunction.VLookup(UBound(skuarray), lookup_range, 4, False)
cost = cost + skucost
Next i
GoodsCost = cost
End Function
Well, it seems like now the problem is solved. Of course, it works only if make an assumption that dashes(-) are not present in product descriptions. But it can be set up in product list. The other opportunity is to use another delimeter (for example "/"). We can use Ctrl+F to find all combinations like "x -" and replace them with "x /")
Function GoodsCost(str)
Dim answer As Double
Set Products = Worksheets("Products").Range("B:E")
larray = Split(str, " - ")
For i = LBound(larray) To UBound(larray)
sku = Split(larray(i), "x ")
Price = Application.WorksheetFunction.VLookup(sku(1), Products, 4, False) * sku(0)
answer = answer + Price
Next i
GoodsCost = answer
End Function
Below you find a UDF (User Defined Function) which you can use in your worksheet. After installing it in a standard code module (VBE names these like "Module1") you can call it from the worksheet like =CostOfGoods($A2) where A2 is the cell containing and order line as you have described.
Option Explicit
Function CostOfGoods(Cell As Range) As Single
' 15 Jan 2018
Const Delim As String = " - "
Dim Fun As Single ' function return value
Dim Sale As Variant
Dim Sp() As String
Dim i As Long
Dim PriceList As Range
Dim Qty As Single, Price As Single
Dim n As Integer
Sale = Trim(Cell.Value)
If Len(Sale) Then
Sp = Split(Sale, Delim)
Do While i <= UBound(Sp)
If InStr(Sp(i), "x ") = 0 Then
If Not ConcatSale(Sp, i, Delim) Then Exit Do
End If
i = i + 1
Loop
With Worksheets("Products")
i = .Cells(.Rows.Count, "B").End(xlUp).Row
' price list starts in row 2 (change as required)
Set PriceList = Range(.Cells(2, "B"), .Cells(i, "E"))
End With
For i = 0 To UBound(Sp)
Qty = Val(Sp(i))
n = InStr(Sp(i), " ")
Sp(i) = Trim(Mid(Sp(i), n))
On Error Resume Next
Price = Application.VLookup(Sp(i), PriceList, 4, False)
If Err Then
MsgBox "I couldn't find the price for" & vbCr & _
Sp(i) & "." & vbCr & _
"The total cost calculated excludes this item.", _
vbInformation, "Price not found"
Price = 0
End If
Fun = Fun + (Qty * Price)
Next i
End If
CostOfGoods = Fun
End Function
Private Function ConcatSale(Sale() As String, _
i As Long, _
Delim As String) As Boolean
' 15 Jan 2018
Dim Fun As Boolean ' function return value
Dim x As Long, f As Long
x = UBound(Sale)
If (i > 0) And (i <= x) Then
i = i - 1
Sale(i) = Sale(i) & Delim & Sale(i + 1)
For f = i + 1 To x - 1
Sale(f) = Sale(f + 1)
Next f
Fun = True
End If
If Fun Then ReDim Preserve Sale(x - 1)
ConcatSale = Fun
End Function
I have tested this and it works with dashes in product description:
Function GoodsCost(str, Optional strDelim As String = " ")
larray = Split(str, " ")
'split the cell contents by space
Set lookup_range = Worksheets("Products").Range("B:E")
'set lookup range
For i = LBound(larray) To UBound(larray) 'loop through array
nextproduct:
LPosition = InStr(larray(i), "x") 'find multiplier "x" in string
If LPosition = Len(larray(i)) Then 'if the last character is x
If Product <> "" Then GoTo lookitup 'lookup product
Quantity = larray(i) 'get quantity
Else
Product = Product & " " & larray(i) 'concatenate array until we get a full product description to lookup with
End If
Next i
lookitup:
If Right(Product, 2) = " -" Then Product = Left(Product, Len(Product) - 2)
If Left(Product, 1) = " " Then Product = Right(Product, Len(Product) - 1)
'above trim the Product description to remove unwanted spaces or dashes
cost = Application.WorksheetFunction.VLookup(Product, lookup_range, 4, False)
Quantity = Replace(Quantity, "x", "")
GoodsCost = cost * Quantity
MsgBox Product & " # Cost: " & GoodsCost
Product = ""
If i < UBound(larray) Then GoTo nextproduct
End Function
I'd use Regular Expressions to solve this. First it finds in the string were the 'delimiters' are by replacing the - with ; detecting only - that are next to a number followed by an x (i.e. a multiplier so ignoring - in product names). It then splits each of these results into a quantity and the product (again using RegEx). It then finds the product in your data and returns the cost of goods. If there is an error, or the product isn't in your data it returns a #Value error to show that there is an issue.
Public Function GoodsCost(str As String) As Double
Dim lookup_range As Range, ProductMatch As Range
Dim v, Match
Dim qty As Long
Dim prod As String
Dim tmp() As String
On Error GoTo err
Set lookup_range = Worksheets("Products").Range("B:E")
With CreateObject("vbscript.regexp")
.Global = True
.ignorecase = True
.pattern = "(\s\-\s)(?=[0-9]+x)"
If .test(str) Then
tmp = Split(.Replace(str, ";"), ";")
Else
ReDim tmp(0)
tmp(0) = str
End If
.pattern = "(?:([0-9]+)x\s(.+))"
For Each v In tmp
If .test(v) Then
Set Match = .Execute(v)
qty = Match.Item(0).submatches.Item(0)
prod = Trim(Match.Item(0).submatches.Item(1))
Set ProductMatch = lookup_range.Columns(1).Find(prod)
If Not ProductMatch Is Nothing Then
GoodsCost = GoodsCost + (qty * ProductMatch.Offset(0, 3))
Else
GoodsCost = CVErr(xlErrValue)
End If
End If
Next v
End With
Exit Function
err:
GoodsCost = CVErr(xlErrValue)
End Function
I need to loop this section and overwrite the x marked positions with my variable x value but if i use it as it is shown on the pic nothings happen. If i enter any value like 1 or 2 instead of x it works. How can i use a variable instead of a value in these places?
Here is also the code:
For j = 1 To SumPositionen
If Sheets("Datenverarbeitung").Cells(Z, 4) = tempCommodityForm Then
session.findById("wnd[0]/usr/tabsTAB_DETAILS/tabpTAB_MF/ssubTABMF:/HERA/TRDMF10:2023/tbl/HERA/TRDMF10TC_2023/ctxt/HERA/TRDINOUT_S-MATNR[1,x]").Text = Sheets("Datenverarbeitung").Cells(a, 5) 'Eingabe Materialnummer in 1. Position
session.findById("wnd[0]/usr/tabsTAB_DETAILS/tabpTAB_MF/ssubTABMF:/HERA/TRDMF10:2023/tbl/HERA/TRDMF10TC_2023/txt/HERA/TRDINOUT_S-MFQUAN[2,x]").Text = Sheets("Datenverarbeitung").Cells(a, 6) 'Eingabe Menge in 1. Position
session.findById("wnd[0]/usr/tabsTAB_DETAILS/tabpTAB_MF/ssubTABMF:/HERA/TRDMF10:2023/tbl/HERA/TRDMF10TC_2023/ctxt/HERA/TRDINOUT_S-MFU[3,x]").Text = Sheets("Datenverarbeitung").Cells(a, 7) 'Eingabe UoM
x = x + 1
End If
a = a + 1
Next j
session.findById("wnd[0]/usr/tabsTAB_DETAILS/tabpTAB_MF/ssubTABMF:/HERA/" & _
"TRDMF10:2023/tbl/HERA/TRDMF10TC_2023/ctxt/HERA/TRDINOUT_S-MATNR[1,x]").Text
Here your string includes the literal value "x". What you really want is likely something more like:
session.findById("wnd[0]/usr/tabsTAB_DETAILS/tabpTAB_MF/ssubTABMF:/HERA/" & _
"TRDMF10:2023/tbl/HERA/TRDMF10TC_2023/ctxt/HERA/TRDINOUT_S-MATNR[1," & x & "]").Text
So something like:
Dim s As String, sht As Worksheet
'....
'....
Set sht = Sheets("Datenverarbeitung")
s = "wnd[0]/usr/tabsTAB_DETAILS/tabpTAB_MF/ssubTABMF:/HERA/" & _
"TRDMF10:2023/tbl/HERA/TRDMF10TC_2023/ctxt/HERA/"
For j = 1 To SumPositionen
If sht.Cells(Z, 4) = tempCommodityForm Then
session.findById(s & "TRDINOUT_S-MATNR[1," & x & "]").Text = sht.Cells(a, 5) 'Eingabe Materialnummer in 1. Position
session.findById(s & "TRDINOUT_S-MFQUAN[2," & x & "]").Text = sht.Cells(a, 6) 'Eingabe Menge in 1. Position
session.findById(s & "TRDINOUT_S-MFU[3," & x & "]").Text = sht.Cells(a, 7) 'Eingabe UoM
x = x + 1
End If
a = a + 1
Next j
define data type to variable link string and integer
I need to add brackets around the numbers in a string found in cells on my Excel worksheet.
For example, say I am given:
913/(300+525)
I need to get this in return:
[913]/([300]+[525])
The equations are fairly simple, should only have to deal with + - * / ( ) characters.
I attempted looping through the string character by character using the MID function but I can't get the loop(s) working correctly and end up getting a jumbled mess of random brackets and numbers back. I also considered using regular expressions but I've never used them before and have no idea if this would be a good application.
Please let me know if you need anything else. Thank you for your time!
They can be decently long. Here is another example:
I have:
(544+(1667+1668+1669+1670+1671+1672+1673)-1674)
But I need:
([544]+([1667]+[1668]+[1669]+[1670]+[1671]+[1672]+[1673])-[1674])
I just threw this together but it should work
Function generateBrackets(Equation As String) As String
Dim temp As String
Dim brackets As Boolean
Dim x 'If we're using Option Explicit, or just to be safe
For x = 1 To Len(Equation)
If Not IsNumeric(Mid(Equation, x, 1)) And brackets = False Then
temp = temp & Mid(Equation, x, 1)
ElseIf Not IsNumeric(Mid(Equation, x, 1)) And brackets = True Then
temp = temp & "]" & Mid(Equation, x, 1)
brackets = False
ElseIf IsNumeric(Mid(Equation, x, 1)) And brackets = False Then
temp = temp & "[" & Mid(Equation, x, 1)
brackets = True
ElseIf IsNumeric(Mid(Equation, x, 1)) And brackets = True Then
temp = temp & Mid(Equation, x, 1)
End If
Next x
generateBrackets = temp
End Function
Here is a way which caters for Decimal numbers.
'~~> Add here whatever operators your equation
'~~> is likely to have
Const delim As String = "+()-/"
Sub Sample()
Dim MyAr
Dim sSamp As String
sSamp = "(5.44+(16.67+1668+1669+1670+1671+1672+1673)-1674)"
MyAr = Split(GetNewString(sSamp))
For i = 0 To UBound(MyAr)
sSamp = Replace(sSamp, MyAr(i), "[" & MyAr(i) & "]")
Next i
Debug.Print sSamp
End Sub
Function GetNewString(s As String) As String
Dim sTemp As String
sTemp = s
For i = 1 To Len(delim)
sTemp = Replace(sTemp, Mid(delim, i, 1), " ")
Next i
Do While InStr(1, sTemp, " ")
sTemp = Replace(sTemp, " ", " ")
Loop
GetNewString = Trim(sTemp)
End Function
Input
"(5.44+(16.67+1668+1669+1670+1671+1672+1673)-1674)"
Output
([5.44]+([16.67]+[1668]+[1669]+[1670]+[1671]+[1672]+[1673])-[1674])
I want to simulate a binomial distribution where the price of something can only go up or down with the probability of p that is 50% this time.
My variables:
S=100 (the basic value)
u=1,1 (how much the value goes up in each experiment if it goes up)
d=1/u (how much the value goes down in each experiment if it goes down)
p=0.5 (probability)
n=400 (number of experiments)
I did not declare these variables, because I want to read these values from specific cells.
My code (for the first step):
Sub BINOM()
S = Range("L4").Value
u = Range("M4").Value
d = Range("N4").Value
p = Range("O4").Value
n = Range("P4").Value
v = Rnd()
If v > p Then
Range("B2").Value = S * u
Else
Range("B2").Value = S * d
End If
End Sub
The result of the second experiment (that should be written in the B3 cell) has to be calculated from the result of the first experiment and so on but not with using the same random number.
I'll try my best but I just removed Excel in favor of Calc which doesn't support the same type of language as far as I can tell.
Sub BINOM()
Dim intCounter, v
S = Range("L4").Value
u = Range("M4").Value
d = Range("N4").Value
p = Range("O4").Value
n = Range("P4").Value
Range("B1").Value = s
For intCounter = 2 to n
'//If this creates an error then just remove it.
'//It should keep the same random number from appearing over and over.
Randomize
'//Create new Random number in v
v = Rnd()
If v > p Then
Range("B" & intCounter).Value = Range("B" & (intCounter - 1)).Value * u
Else
Range("B" & intCounter).Value = Range("B" & (intCounter - 1)).Value * d
End If
Next intCounter
End Sub
Let me know if that works out for you or if any errors appear. Updated to base each cell from data given of previous cell.