Alright what did I do wrong? Found this on the web, tried it and got a type mismatch. Just trying to make my code more concise by having the variables define themselves, for e.g. Y(10), Y(11), Y(12), Y(13), or Y10 ... Y13, so I'll have 4 variables at the end of the sub. Y10-13 are NOT the cell positions, but they are related. Look Below!
variable a refers to the actual row, so say Y10 = 400 is the only entry on row 5, row 7 has Y10 = 7 and Y12 = 3. I did not define this in the code because this section runs as function(a) and a is defined before the function itself such that the sub checks for a=1 to the last row.
Dim Y(10 To 13) As Integer 'these are just variables
Dim a as long 'this is an arbitrary row number defined before the function
For I = 10 to 13 'These are column numbers in the actual data range
If .Worksheets("15SK").Cells(a, I) <> "" Then
Y(I) = .Worksheets("15SK").Cells(a, I).value 'Y(I) basically takes the value of the cell (a,I)
End If
Next
I basically need a dynamic variable Y(I) or YI (in any form really) because later sections of my code calls for it. I'll share another section to state my point, but its difficult for me to translate what I'm doing in this next section:
For I = 10 To .Worksheets("15SK").Cells(2, Columns.Count).End(xlToLeft).Column 'All models
If .Worksheets("15SK").Cells(a, I) <> "" Then 'If product model order > 0
'removed a section of code here
j = j + 3 'step 3
If ItemType = "Adaptor" And Y > X1 And DUP <> 1 Then
Y1 = Y1 + Y(I)
If ItemType = "Adaptor" And Y1 > X1 Then 'adding another duplicate
DOwb.Worksheets(1).Cells(j, 3) = .Worksheets("15SK").Cells(2, I) 'First DO product model row
DOwb.Worksheets(1).Cells(j - 1, 1) = Y1 - X1 'Excess Qty to be charged
DOwb.Worksheets(1).Cells(j - 3 - 1, 1) = Y(I) - (Y1 - X1) 'Making the previous row's Qty FOC by no. of CD - no. of previous
DOwb.Worksheets(1).Cells(j - 1, 2) = "pcs"
DOwb.Worksheets(1).Cells(j - 1, 3) = Application.WorksheetFunction.VLookup(DOwb.Worksheets(1).Cells(j, 3), .Worksheets("Catalogue").Range("catalogue"), 2, False) 'Model Description
JFOC = j
j = j + 3 'step 3
DUP = 1 'stops the duplication
ElseIf Y1 = X1 Then
JFOC = j
End If
Y1 = 0
End If
Sorry guys really new to VBA, or coding for the matter. Terrific help so far!
Y10 cannot be the name of variable (because it could be confused with cell Y10). Code that attempts to use such variable names will not work. Try other name, for example y_10 will be fine.
Related
I have extensive nested for loops that would take about 3 hours to run through to the end.
Inside the loop I write and read to sheet cells.
But every 15 mins (pretty regular frequency) I get a type mismatch error.
The code is too extensive to post in its entirity here but this is a representative snip of the types of operations I am doing on it:
Set msDesign = msApp.Design
Dim base_x(1 To 5) As Double, base_y(1 To 5) As Double, base_z(1 To 5) As Double
'================================================================
'======================== Apply vars section ====================
'================================================================
' Measure Hull
MeasureHull (fname)
' Read Master Section Points ================== HARDCODED =============
GetPoints
For ro = 1 To 3
base_x(ro) = Module1.CtrlPointX(1, ro, 3)
base_y(ro) = Module1.CtrlPointY(1, ro, 3)
base_z(ro) = Module1.CtrlPointZ(1, ro, 3)
Next ro
' Calculate other section points ==================== HARDCODED ============
For cl = 1 To 2
For ro = 1 To 3
x_norm = Module1.CtrlPointX(1, ro, cl) / base_x(ro)
Sheet3.Cells(9, 2 + cl) = x_norm
yscale = Sheet3.Cells(10, 2 + cl)
zscale = Sheet3.Cells(11, 2 + cl)
Debug.Print ("Debug - fname =" & Right(fname, 20) & " / yscale= " & yscale & " / base_y= " & base_y(ro) & " / zscale= " & zscale)
msDesign.Surfaces(1).SetControlPoint ro, cl, Module1.CtrlPointX(1, ro, cl), base_y(ro) * yscale, (base_z(ro) - Range("_base_draft")) * zscale + Range("_base_draft")
Next ro
Next cl
' Rescale the surfaces in y
yscale2 = Sheet3.Cells(13, 3)
msDesign.Surfaces(1).ReScale 1, yscale2, 1, 0, 0, Range("_base_draft")
CorrectFB
If I enter debug mode and press play the code continues to run without errors for the next 15 mins.
My goal is to run through the loop, without skipping any iterations and without stopping due to type mismatch errors.
There is a very similar issue here:
Excel VBA: Type Mismatch
I suppose the error is caused by an excel sheet value returning an N/A error as in the reference question. Instead of just failing an IF statement and bypassing that iteration as proposed on that question I would like to deal with the issue and run through that iteration without the need for my input on the middle of the loop.
I cannot extract the postal/zip code of a given address cell that comes like this :
"108, avenue du Grand Sud 37 170 CHAMBRAY les TOURS".
I have used :
=RECHERCHE(9^9;--("0"&STXT(A2;MIN(CHERCHE({0.1.2.3.4.5.6.7.8.9};A2&"0 123456789"));LIGNE($1:$100))))
Which sometimes works, sometimes not depending on the street number starting the address (here "108,").
The problem is the space of the pattern "37 170". I would like to remove the blank space in the pattern. Is there a regex way to search this pattern "## ###", and then to remove this poisonous blank space?
Thank you for your tricks.
I have tried this piece of code :
Function toto(r, Optional u = 0)
Application.Volatile
Dim i%, j%, adr$, cp$, loca$, x
x = Split(r)
For i = 0 To UBound(x)
If x(i) Like "#####" Then Exit For
Next
If i > UBound(x) Then
adr = r.Value 'facultatif
Else
cp = x(i)
For j = 0 To i - 1: adr = adr & x(j) & " ": Next
adr = Left$(adr, Len(adr) + (Len(adr) > 1))
For j = i + 1 To UBound(x): loca = loca & x(j) & " ": Next
loca = Left$(loca, Len(loca) + (Len(loca) > 1))
End If
x = Array(adr, cp, loca)
If 0 < u And u < 4 Then toto = x(u - 1) Else toto = x
End Function
The above code works fine for splitting addresses including street number, zip code, and city name. But it does not work when the zip code is ## ### = 2 digit integer - space - 3 digit integer.
Edit: 01 June 2021
Since it seems my question is not clear enough, let's rephrase :
Given an Excel worksheet containing in each cell of column A, from saying A1 down to A10000, complete addresses like this one :
"2 rue Rene cassin Centre Commercial Châlon 2 Sud 71 100 CHALON SUR SAONE"
or this one :
"15, Rue Emile Schwoerer 68 000 COLMAR"
Where "71 100" and "68 000" are a zip code in incorrect format because of the extra space between the 2 first digits and 3 last digits.
I need to split the Ai cell content in order to obtain :
in cell Bi : the text (street, etc.) placed left before the 2 first digits of the "wrong" zip code,
in cell Ci : the zip code with its correct format ("71100" and not "71 100"),
in cell Di : the text (city name) after the zip code.
It's a kind of left and right extraction around the zip code.
The above code that I have posted does not work.
In order to obtain the correct zip code format, I have tried the regex following function :
Function FindReplaceRegex(rng As Range, reg_exp As String, replace As String)
Set myRegExp = New RegExp
myRegExp.IgnoreCase = False
myRegExp.Global = True
myRegExp.Pattern = reg_exp
FindReplaceRegex = myRegExp.replace(rng.Value, replace)
End Function
But I am unable to determine the correct regular expression pattern to get rid of the space in the zip code.
PEH gave me the following pattern :
(.*)([0-9]{2} ?[0-9]{3})(.*)
When using the function, I have tried to define the replacement pattern by:
(.*)([0-9]{2}[0-9]{3})(.*)
But it would not work. Hope this will clarify my question.
Any idea is welcome. Thanks
If these input strings always have the same pattern, try:
=CONCAT(FILTERXML("<t><s>"&SUBSTITUTE(A1," ","</s><s>")&"</s></t>","//s[.*0=0]"))
Depending on your needs/edge-cases, you could add more xpath expressions.
If this is VBA, I have a fix for you (please forgive the crappy naming convention, I'm scribbling this down in work while waiting for SQL to refresh):
Sub test1()
a0 = Cells(1, 1) 'Get the text, in this case "108, avenue du Grand Sud 37 170 CHAMBRAY les TOURS"
aa = Replace(a0, ",", " ") 'Make all delimiters of same type, so removing commas, you may need to add more replace work here?
ab = Application.Trim(aa) 'Reduce all whitespace to single entries, i.e. " " rather than " "
ac = Split(ab, " ", -1) 'Now split by that single whitespace entry
Dim txt()
i2 = 0
lastIsNumeric = False
For i1 = 0 To UBound(ac) - 1 'Step through each entry in our "split" list
If IsNumeric(ac(i1)) = True And IsNumeric(ac(i1 + 1)) = True Then
'Two numbers back to back, join
ReDim Preserve txt(i2)
txt(i2) = ac(i1) + ac(i1 + 1)
i2 = i2 + 1
i1 = i1 + 1
Else
'Not two numbers back to back, don't join
ReDim Preserve txt(i2)
txt(i2) = ac(i1)
i2 = i2 + 1
End If
Next i1
If IsNumeric(ac(UBound(ac))) = False Then
'Need to add last entry to txt()
ReDim Preserve txt(UBound(txt) + 1)
txt(UBound(txt)) = ac(UBound(ac))
End If
End Sub
edit 2021-06-01:
The above will generate a list (txt) of all the entries within your address. You can then reassemble if you wish, or extract out the postcode only.
If you want it as a function, then it would be:
Public Function getPostcode(a0)
aa = Replace(a0, ",", " ")
ab = Application.Trim(aa)
ac = Split(ab, " ", -1)
Dim txt()
i2 = 0
lastIsNumeric = False
For i1 = 0 To UBound(ac) - 1
If IsNumeric(ac(i1)) = True And IsNumeric(ac(i1 + 1)) = True Then
'Two numbers back to back, join
ReDim Preserve txt(i2)
txt(i2) = ac(i1) + ac(i1 + 1)
i2 = i2 + 1
i1 = i1 + 1
Else
'Not two numbers back to back, don't join
ReDim Preserve txt(i2)
txt(i2) = ac(i1)
i2 = i2 + 1
End If
Next i1
If IsNumeric(ac(UBound(ac))) = False Then
'Need to add last entry to txt()
ReDim Preserve txt(UBound(txt) + 1)
txt(UBound(txt)) = ac(UBound(ac))
End If
'Re-assemble string for return
rtnTxt = ""
For i1 = 0 To UBound(txt)
rtnTxt = rtnTxt & " " & txt(i1)
Next i1
getPostcode = rtnTxt
End Function
i have a code that copies and rewrites anything thats between "(" and ")", but now i have different type of data which do not end with ")" so, i need it to stop when it reaches the last character in cell. Maybe it is dumb question but i cant seem to find how to fix my problem. I am a student and total newbie in vba (5 days ago i didn't know what vba is...) also sorry for my bad english.
I've tried to search (in here, google, youtube) but i couldnt find anything i need
'zaciatok=start koniec=end dlzka=length
Do While Mid(LookInHere, y, 1) <> ""
If Mid(LookInHere, Z, 1) = "(" Then
zaciatok = Z
End If
If Mid(LookInHere, y, 1) = ")" Then
koniec = y
dlzka = (koniec - 1) - zaciatok
dlzka = Abs(dlzka)
SplitCatcher = Mid(LookInHere, zaciatok + 1, CStr(dlzka))
MsgBox SplitCatcher
End If
y = y + 1
Z = Z + 1
Loop
In your specific implementation, one option is to modify your Do While ... loop to also test against the length of the string. That line would look something like:
Do While Mid(LookInHere, y, 1) <> "" And y < Len(LookInHere)
That modification tells the statement that it should terminate the loop when the iterating variable y goes past the length of the statement.
Another option is to change it from a Do While loop to a For loop. It would read something like:
For i = 1 to Len(LookInHere)
MsgBox Mid(LookInHere, i, 1)
'Input your logic here
Next i
The problem is that each of these versions is relatively inefficient, looping through each letter in a string a performing a calculation. Consider using built-in Excel functions. The Instr returns the position of a character, or a zero if it is not found. As an example, Instr("Abcdef", "b") would return the number 2, and Instr("Abcdef", "k") would return zero. You can replace the entire loop with these two function calls.
Z = Instr(LookInHere, "(")
y = Instr(LookInHere, ")")
If y = 0 Then y = Len(LookInHere)
Final note: if your patterns begin to get more and more complex, consider reviewing and implementing regular expressions.
You can use Right(LookInHere, 1) to get the last character of LookInHere
Ive got some code which used 5 different constants (FC) i would like to instead use an average of them which i could work out in a cell on excel.
If there is any other glaring mistakes or improvements which could be made, they would be greatly appreciated.
Dim rainfall(), evaporation(), obs_q(), FC() As Double
Dim available_w(), overflow(), interflow() As Double
Dim ccrain, ccevaporation, i, j As Integer
'amount of data
Do
m = Worksheets("Hydrological_Data").Cells(6 + n, 2)
If m <> "" Then
n = n + 1
Else
Exit Do
End If
Loop
ReDim rainfall(n + 1), evaporation(n + 1), obs_q(n + 1) As Double
For i = 0 To n - 1
obs_q(i) = Worksheets("Hydrological_Data").Cells(6 + i, 3)
rainfall(i) = Worksheets("Hydrological_Data").Cells(6 + i, 4) * (1 + ccrain / 100)
evaporation(i) = Worksheets("Hydrological_Data").Cells(6 + i, 5) * (1 + ccevaporation / 100)
Next i
'initial conditions
ReDim available_w(n - 1, 5), overflow(n - 1, 5), interflow(n - 1, 5) As Double
available_w(0, 1) = FC(1) + rainfall(0) - evaporation(0)
available_w(0, 2) = FC(2) + rainfall(0) - evaporation(0)
available_w(0, 3) = FC(3) + rainfall(0) - evaporation(0)
available_w(0, 4) = FC(4) + rainfall(0) - evaporation(0)
available_w(0, 5) = FC(5) + rainfall(0) - evaporation(0)
For j = 1 To 5
If available_w(0, j) > FC(j) Then
overflow(0, j) = available_w(0, j) - FC(j)
available_w(0, j) = FC(j)
Else
overflow(0, j) = 0
End If
If available_w(0, j) > 0 Then
interflow(0, j) = available_w(0, j) * a
Else
interflow(0, j) = 0
End If
Some more coding advice...
Please don't use exit (or goto's for that matter). It's a bad practice. Also I suggest you reference your workbook as well and not just the worksheet.
You could do something like the following, for example:
Dim n As Long
n = 0 'as already suggested in another post, n needs to be initialized with whatever value you see fit
Do While ThisWorkbook.Worksheets("Hydrological_Data").Cells(6 + n, 2) <> ""
n = n + 1
Loop
Now as far as the average of FC(1)...FC(5) is concerned, I'm probably not getting where your problem is, because it's fairly easy compared to the code you've already written so far...
In any case, here's the obvious way to do it:
Dim FCsum As Double
Dim FCaverage As Double
Dim i As Integer
FCsum = 0
For i = 1 To 5 Step 1
FCsum = FCsum + FC(i)
Next i
FCaverage = FCsum / 5
Now, if you have calculated this average in a cell using just the AVERAGE formula, then it's even easier. You will just use a reference to this cell like so:
ThisWorkbook.Worksheets("Hydrological_Data").Range("A1").value 'or whichever cell your average is being calculated in
and then use it in whatever calculation you want to perform.
First, some coding advice. The Dim statements with AS at the ends only declares the last variable AS the stated type. See https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/dim-statement
Second, n is used without initialization. It is good from to initialize variables instead of using the initialization from the compiler. This will work in most cases but if for some reason the code is re-entered or re-used it will have the wrong n to start.
I ran into this recently when creating code and testing using the debugger. I hop around in the debugger and sometimes the loops don't run because I did not initialize the loop variable.
I have a list of products with the ID and the picture name. One entry per picture, instead of one entry per product and the pictures in columns as I need it. If the file had only a few entries, the manual procedure I guess it would be to cut all the picture names for the same product, paste (transpose) and remove the entries without names. But since the file has over 100,000 entries, does anyone know how to do this using VBA?
EXAMPLE:
What I have...
product_id; picture_name
1; picture1.jpg
1; picture2.jpg
1; picture3.jpg
2; picture4.jpg
3; picture5.jpg
3; picture6.jpg
What I need...
product_id; 1st_picture; 2nd_picture; 3rd_picture...
1; picture1.jpg; picture2.jpg; picture3.jpg
2; picture4.jpg
3; picture5.jpg; picture6.jpg
Thank so you much in advance for your help.
I guess this solves your problem
Compare two consecutive rows one by one
If two rows matches,Take the corresponding value in 2nd column of 2nd row put the value in next to 2nd column of 1st row and delete the 2nd row
If not matches skip the previous step and go for comparison of next two rows.
Here is the Code
Sub SortPics()
i = 2
Do
Flag = False
VarComp1 = Sheets("YourSheetName").Cells(i, 1).Value
VarComp2 = Sheets("YourSheetName").Cells(i + 1, 1).Value
If VarComp1 = VarComp2 And VarComp2 <> "" Then
Set VarSec1 = Sheets("YourSheetName").Cells(i, 2)
Set VarSec2 = Sheets("YourSheetName").Cells(i + 1, 2)
VarSec1.Offset(0, 1 + j).Value = VarSec2.Value
Sheets("YourSheetName").Cells(i + 1, 1).EntireRow.Delete
i = i - 1
Flag = True
End If
i = i + 1
If Flag = True Then
j = j + 1
Else
j = 0
End If
Loop While VarComp1 <> ""
End Sub