i'm trying to move words after the first space from 30th character in a string to the next row(i+1) added and remove those words moved to the next row from the current row(i). The code is giving Run-time error '5': Invalid procedure call or argument error message at Cells(i, 1).Value = Left(Cells(i, 1), InStr(30, Cells(i, 1), " ") - 1) line.
Sub TextLimit_02()
Dim i As Long
Dim CelLen As Long
For i = 1 To 50
CelLen = Len(Cells(i, 1))
If CelLen > 40 Then
Rows(i + 1).Insert
Cells(i + 1, 1).Value = Mid(Cells(i, 1), InStr(30, Cells(i, 1), " ") + 1, Len(Cells(i,
1).Value) - InStr(30, Cells(i, 1), " "))
Cells(i, 1).Value = Left(Cells(i, 1), InStr(30, Cells(i, 1), " ") - 1)
Else
End If
Next i
End Sub
Your code doesn't account for the possibility that in a string longer than 40, there are no spaces after position 30.
Breaking the logic down into steps makes it easy to detect this, and possibly add more code to deal with it
Sub TextLimit_02()
Dim i As Long
Dim CelLen As Long
Dim idx As Long
Dim CellString As String
Dim LeftPart As String
Dim RightPart As String
For i = 1 To 50
CellString = Cells(i, 1).Value2
CelLen = Len(CellString)
If CelLen > 40 Then
idx = InStr(30, CellString, " ")
If idx > 0 Then
Rows(i + 1).Insert
LeftPart = Left$(CellString, idx - 1)
RightPart = Mid$(CellString, idx + 1)
Cells(i, 1) = LeftPart
Cells(i + 1, 1) = RightPart
If idx > 40 Then
' there remains >40 characters in Cells(i, 1)
End If
Else
' No spaces after position 30. Cells(i, 1) remains longer than 40
End If
End If
Next i
End Sub
Note that if you split a lot of strings, your data may end up spanning past row 50. With For i = 1 to 50 you will miss processing some string in that case.
This code should do what you intend. Please test it and let me know what it does wrong.
Sub TextLimit_02()
' 269
Dim Txt As String ' text
Dim Tail As String ' tail end of Txt to be moved
Dim p As Long ' position of character in string
Dim R As Long ' loop counter: rows
Application.ScreenUpdating = False
' start from the end of column A to 2nd row
For R = Cells(Rows.Count, "A").End(xlUp).Row To 2 Step -1
Txt = Trim(Cells(R, "A").Value) ' remove leading/trailing blanks
p = InStr(Mid(Txt, 30), " ")
Tail = Trim(Mid(Txt, p + 30)) ' in case of double space
If Len(Tail) Then ' skip if no Tail
Cells(R, "A").Value = Left(Txt, p + 29)
Rows(R + 1).Insert
Cells(R + 1, "A").Value = Tail
End If
Next R
Application.ScreenUpdating = True
End Sub
Try this code:
Sub WrapText()
Const MIN_CARRY_POS = 30, MAX_LEN = 40, CARRY_SYMBOL = " " 'preferences
Dim cl As Range, txt As String, pos As Long, slice As Long
Application.ScreenUpdating = False
Set cl = ThisWorkbook.Worksheets(1).Range("A1")
Do 'main row loop
txt = RTrim(cl.Text)
Select Case Len(txt)
Case 0: Exit Do
Case Is > MAX_LEN
Do While Len(txt) > MAX_LEN 'a nested loop to process text that needs to be carried over
pos = InStr(MIN_CARRY_POS, txt, CARRY_SYMBOL)
If pos < 1 Then pos = MAX_LEN 'if no CARRY_SYMBOL after MIN_CARRY_POS then cut the string at MAX_LEN
slice = WorksheetFunction.Min(pos, MAX_LEN)
cl.Insert xlDown
cl.Offset(-1).Value = Mid(txt, 1, slice) 'output the head
txt = LTrim(Mid(txt, slice + 1)) 'get the rest of the txt
Loop
cl.Value = txt 'output the rest <= MAX_LEN
End Select
Set cl = cl.Offset(1) 'move to the next row
Loop
Application.ScreenUpdating = True
End Sub
Before
After
Related
The macro is written to return the number of letter differences (insertions, replacements, or deletions) of two words (case sensitive).
It is suppose to format and output in phrases
1-2 Letters off,
1-2 Letters off, Same Starting Letter,
3-4 Letters off,
3-4 Letters off, Same Starting Letter and
5 or more letters off, CHECK
It is only outputting
1-2 Letters off, Same Starting Letter,
3-4 Letters off, Same Starting Letter and
5 or more Letters off, CHECK
I would like the formatting to stay the same for now.
Sub Test_HW_Formatter()
'declare the variables
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim testNames As Integer
Dim responses As Integer
Dim printRow As Integer
Dim name As String
Dim count As Integer
Dim coding As String
Dim statLetter As Boolean
Dim tempCount As Integer
Dim tempResp As String
'the queues for the entries, the respective counts, and respective codes
Dim words As Object
Set words = CreateObject("System.Collections.Queue")
Dim counts As Object
Set counts = CreateObject("System.Collections.Queue")
Dim codes As Object
Set codes = CreateObject("System.Collections.Queue")
'set the variables
printRow = 3
testNames = Selection.Columns.count
responses = Selection.Rows.count - 1
Cells(4, 3).Value = Selection(4)
startLetter = True
'make the header
Cells(1, 1).Value = "Name"
Cells(1, 2).Value = "Response"
Cells(1, 3).Value = "Count"
Cells(1, 4).Value = "Code"
Cells(1, 5).Value = "Agency close matches"
Cells(1, 6).Value = "N=" + Trim(Str(responses))
Cells(1, 6).Interior.Color = RGB(255, 255, 204)
Cells(1, 6).HorizontalAlignment = xlCenter
For i = 1 To 5
Cells(1, i).Interior.Color = RGB(1, 139, 175)
Cells(1, i).Font.Color = RGB(255, 255, 255)
Cells(1, i).HorizontalAlignment = xlCenter
Next i
'get the information and put it in the queues
For i = 0 To (testNames - 1)
name = Selection(i + 1).Value
For j = 1 To responses
count = 1
If Not Selection(j * testNames + i + 1) = "" Then
For k = 1 To (responses - j)
If Not Selection((j + k) * testNames + i + 1).Value = "" Then
If Trim(UCase(Selection(j * testNames + i + 1).Value)) = Trim(UCase(Selection((j + k) * testNames + i + 1).Value)) Then
count = count + 1
Selection((j + k) * testNames + i + 1).Value = ""
End If
End If
Next k
'get the coding
coding = ""
ld = Levenshtein(name, Trim(UCase(Selection(j * testNames + i + 1))))
If Mid(testName, 1, 1) = Mid(sample, 1, 1) Then
startLetter = True
Else
startLetter = False
End If 'if for starting letter
Select Case ld
Case 0
coding = "Exact Match"
Case 1
If startLetter = True Then
coding = "1-2 Letters off, Same Starting Letter"
Else
coding = "1-2 Letters off"
End If
Case 2
If startLetter = True Then
coding = "1-2 Letters off, Same Starting Letter"
Else
coding = "1-2 Letters off"
End If
Case 3
If startLetter = True Then
coding = "3-4 Letters off, Same Starting Letter"
Else
coding = "3-4 Letters off"
End If
Case 4
If startLetter = True Then
coding = "3-4 Letters off, Same Starting Letter"
Else
coding = "3-4 Letters off"
End If
Case Else
coding = "5 or more Letters off, CHECK"
End Select
'enqueue the values
tempResp = UCase(Mid(Selection(j * testNames + i + 1).Value, 1, 1)) + LCase(Mid(Selection(j * testNames + i + 1).Value, 2, Len(Selection(j * testNames + i + 1).Value)))
words.enqueue (tempResp)
counts.enqueue (count)
codes.enqueue (coding)
End If 'if the cell is not blank
Next j
'print the queues from the ith column
'start the section header
Cells(printRow, 1).Value = name
Cells(printRow, 1).Font.Color = RGB(255, 255, 255)
For k = 1 To 5
Cells(printRow, k).Interior.Color = RGB(1, 139, 175)
Cells(printRow, k).HorizontalAlignment = xlCenter
Next k
tempCount = counts.count
Cells(150, 20 + i).Value = tempCount
For k = 1 To tempCount
Cells(printRow + k, 2).Value = words.dequeue
Cells(printRow + k, 3).Value = counts.dequeue
Cells(printRow + k, 4).Value = codes.dequeue
If Cells(printRow + k, 4).Value = "Exact Match" Then
Cells(printRow + k, 4).Interior.Color = RGB(236, 239, 218)
End If
Next k
printRow = printRow + tempCount + 2
Next i
End Sub
Edited to add counting replicates of the same name, and skip empty values:
Sub Test_HW_Formatter()
Dim arr, numReps As Long, ws As Worksheet, col As Long, c As Range
Dim nm As String, rep As Long, cmp As String
Dim i As Long, dict As Object, tmp
arr = Selection.Value 'inputs
numReps = UBound(arr, 1) - 1 'reps per column
Set ws = Selection.Parent 'sheet with selection
With ws.Range("A1:E1")
.Value = Array("Name", "Response", "Count", "Code", "Agency Close match")
doHeaders .Cells
End With
ws.Range("F1").Value = "N=" & numReps
Set c = ws.Range("A3") 'start of output sections
For col = 1 To UBound(arr, 2) 'loop columns of selection
nm = arr(1, col)
c.Value = nm
doHeaders c.Resize(1, 5) 'format headers
i = 0
Set dict = CreateObject("scripting.dictionary")
For rep = 1 To numReps 'loop values to compare
cmp = arr(rep + 1, col)
If Len(cmp) > 0 Then
If Not dict.exists(cmp) Then
i = i + 1
dict.Add cmp, i
c.Offset(i, 1).Value = cmp
c.Offset(i, 2) = 1
c.Offset(i, 3).Value = MatchCoding(nm, cmp) 'now in separate function
Else
'increment count for existing line
c.Offset(dict(cmp), 2).Value = c.Offset(dict(cmp), 2).Value + 1
End If
End If 'not zero-length
Next rep
Set c = c.Offset(i + 2, 0) 'next set
Next col
End Sub
'return a string summarizing how closeley two terms match
Function MatchCoding(nm As String, cmp As String)
Dim ld As Long, firstMatch As Boolean
firstMatch = (Left(nm, 1) = Left(cmp, 1))
ld = Levenshtein(nm, cmp)
Select Case ld
Case 0: MatchCoding = "Exact Match"
Case 1, 2: MatchCoding = "1-2 Letters off"
Case 3, 4: MatchCoding = "3-4 Letters off"
Case Else: MatchCoding = "5 or more Letters off, CHECK"
End Select
If ld > 0 And ld < 5 Then MatchCoding = MatchCoding & _
IIf(firstMatch, ", Same Starting Letter", "")
End Function
'utility sub for formatting headers
Sub doHeaders(rng As Range)
With rng
.Interior.Color = RGB(1, 139, 175)
.Font.Color = RGB(255, 255, 255)
.HorizontalAlignment = xlCenter
End With
End Sub
Option Explicit
Sub trial()
Dim rng As Range
Dim celladdress As String
Dim myrange As Variant
Dim word As Variant
Set rng = Range("G3:G1000").Find(what:="Description")
rng.Find what:="Description"
celladdress = rng.Address
Dim max As Range
Dim b As Integer
b = Worksheets("Sheet1").Cells(Rows.count, "a").End(xlUp).Row
Set max = Range("G2", celladdress)
For Each word In max
If word = "Moisture Content" Then
Cells(b + 1, 24) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Grading Class" Then
Cells(b + 1, 16) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Zone X Constituent Parts" Then
Cells(b + 1, 17) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Plastic Limit" Then
Cells(b + 1, 18) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Liquid Limit" Then
Cells(b + 1, 19) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Plasticity Index" Then
Cells(b + 1, 20) = word.Offset(0, 1)
Exit For
End If
Next word
Each word In max
If word = "Particle Density" Then
Cells(b + 1, 21) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Optimum Moisture Content" Then
Cells(b + 1, 22) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Maximum Dry Density" Then
Cells(b + 1, 23) = word.Offset(0, 1)
Exit For
End If
Next word
For Each word In max
If word = "Shear Strength at OMC" Then
Cells(b + 1, 15) = word.Offset(0, 1)
Exit For
End If
Next
Dim txt As String
Dim i As Integer
Dim reference As Variant
Dim k As Integer
Dim c As Integer
c = Worksheets("Sheet1").Cells(Rows.count, "a").End(xlUp).Row
txt = Cells(2, 5).Value
reference = Split(txt, " ")
For i = 0 To UBound(reference)
Cells(c + 1, 4).Value = reference(i)
next
txt = Cells(2, 5).Value
reference = Split(txt, " ")
For k = 0 To LBound(reference)
Cells(c + 1, 9).Value = reference(k)
Next k
Dim Last_Row As Long
Last_Row = Range("C3").End(xlDown).Offset(1).Row
Cells(Last_Row, [13]).Value = "Sampling"
Range("C3").Copy Range("C" & Last_Row)
Range("B3").Copy Range("B" & Last_Row)
Range("A3").Copy Range("A" & Last_Row)
Dim rnge As Range
Dim celladdres As String
Set rnge = Range("G3:G1000").Find(what:="Description")
rng.Find what:="Description"
celladdres = rnge.Address.Offset(-1, 50) - Invalid error
Dim maxy As Range
Set maxy = Range("G2", celladdress)
Worksheets("Sheet1").Range(max).Delete
End Sub
Hi i keep getting an invalid qualifer error and im unsure why. Im trying to get the find the next description and then offset the cell so i can delete all the information in the row above and 50 column along. im unsure why the error keep ocurring and what it actually means. any help would be greatly appreicated thanks max
A separate program that I cannot change adds to a spreadsheet and sometimes it duplicates something.
For example:in cell 5, 3
ABC, vbd, S19M-0027757-27760, S19M-0027757-27760(1)
or it could be
ABC, vbd S19M-0027757-27760, S19M-0027757-27760(1)
What I need to do is replace both of them with S19M-0027757-27760(1) so the out come would be:
ABC, vbd, S19M-0027757-27760(1)
So far I have:
For i = 5 To lRow
inputArray = Split(Cells(i, 3).Value, " ")
For j = 0 To (UBound(inputArray) - LBound(inputArray) - 1)
Dim firstString As String
Dim secondString As String
firstString = inputArray(j)
secondString = inputArray(j + 1)
Next
Next
I am thinking the next step would be to compare letter by letter? But what about the comma and (1)?
Try this. Possibly not enough examples to be sure it will work in all cases, but a short test worked.
Sub x()
Dim i As Long, inputArray, j As Long, outputArray(), k As Long
For i = 1 To 3
inputArray = Split(Cells(i, 3).Value, ", ")
For j = LBound(inputArray) To UBound(inputArray)
k = k + 1
ReDim Preserve outputArray(1 To k)
If j = UBound(inputArray) - 1 Then
If inputArray(j + 1) Like inputArray(j) & "(*)" Then
outputArray(k) = inputArray(j + 1)
Exit For
Else
outputArray(k) = inputArray(j)
End If
Else
outputArray(k) = inputArray(j)
End If
Next j
Cells(i, 4).Value = Join(outputArray, ", ")
Erase outputArray: k = 0
Next i
End Sub
Some other way, possible through RegEx:
Sub Test()
Dim RegEx As Object: Set RegEx = CreateObject("VBScript.RegExp")
RegEx.Global = True
RegEx.Pattern = "([A-Z0-9-]{18})(?=.+\1)"
Dim lr As Long, x As Long
With Sheet1
lr = .Cells(.Rows.Count, 3).End(xlUp).Row
For x = 5 To lr
.Cells(x, 3).Value = Replace(Replace(RegEx.Replace(.Cells(x, 3).Value, ""), ", ,", ", "), " ,", ", ")
Next x
End With
End Sub
I agree with #SJR, some more examples would be great to know if the RegEx.Pattern would hold TRUE. I now went with the assumptions of 18-char patterns. It would hold for the current sample data:
Before:
After:
I have the follow script to put a list of people with there know skills in an array and then match the first match with a customer with the same skill. Every time it runs the results are the same. I would like to have it be a random order of the array, but keeping the two columns in the array together. How can I shuffle(rearrange) the array that keeps the rows in the array the same? Or would it be better to erase the array, randomly sort the columns and set the array back up?
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
p = 0
o = 0
For i = 2 To 920
If Cells(i, 12).Value <> Cells(i - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(i, 12).Value
arOne(p, 1) = Cells(i, 13).Value
o = 2
Else
arOne(p, o) = Cells(i, 13).Value
o = o + 1
End If
Next
For i = 2 To 612
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & i), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(i, 2).Value Then
Cells(i, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
GoTo NextIR
End If
Next j
End If
End If
Next o
NextIR:
Next i
End Sub
Multiple loops and multiple access to range objects makes your code very, very slow (I don't know if performance is important).
I would read all necessary data to arrays and use filter and rnd to get a random person with the relevant skill:
Option Explicit
Sub PeopleBusiness()
Dim People, Customers, FilterArray
Dim I As Long, Idx As Long
People = Application.Transpose([L2:L920 & "|" & M2:M8])
Customers = Range("A2:C612").Value2
For I = 1 To UBound(Customers, 1)
FilterArray = Filter(People, Customers(I, 2))
If UBound(FilterArray) > -1 Then
Idx = Round(Rnd() * UBound(FilterArray), 0)
Customers(I, 3) = Left(FilterArray(Idx), InStr(1, FilterArray(Idx), "|") - 1)
End If
Next I
Range("A2:C612").Value = Customers
End Sub
I was able to get done what I needed by erasing the array and redimming it after sorting the data based on a rand() number in the table. It takes about 15 minutes to run 7000 assignment but it is a lot better than 7+ hours it takes to do manually.
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
Application.Calculation = xlAutomatic
StartTime = Timer
NextIR:
ReDim arOne(1000, 15)
p = 0
o = 0
QAlr = Sheets("Sheet1").Range("L" & Rows.Count).End(xlUp).Row
For I = 2 To QAlr
If Cells(I, 12).Value <> Cells(I - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(I, 12).Value
arOne(p, 1) = Cells(I, 13).Value
o = 2
Else
arOne(p, o) = Cells(I, 13).Value
o = o + 1
End If
Next
AQAlr = Sheets("Sheet1").Range("C" & Rows.Count).End(xlUp).Row
AgtLr = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
For I = AQAlr + 1 To AgtLr
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & I), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(I, 2).Value Then
Cells(I, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
Erase arOne()
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Add _
Key:=Range("Table1[[#All],[Random '#]]"), SortOn:=xlSortOnValues, Order:= _
xlDescending, DataOption:=xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
GoTo NextIR
End If
Next j
End If
End If
Next o
Next I
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
MsgBox "Assignments completed in " & MinutesElapsed & " minutes", vbInformation
End Sub
Not entirely sure I got your set-up right but you can try this:
Option Explicit
Sub Assign()
Randomize
Range("C2", Range("C" & Rows.Count).End(xlUp)).ClearContents
Dim R1 As Range: Set R1 = Range("L2:M920") 'People skill table
Dim R2 As Range: Set R2 = Range("A2:B612") 'Cusotmers skill talbe
Dim D0 As Object: Set D0 = CreateObject("scripting.dictionary")
Dim i As Integer, j As Integer, Rand as Integer
For i = 1 To R2.Rows.Count
Rand = Int(R1.Rows.Count * Rnd + 1)
For j = 1 To R1.Rows.Count
If R1.Cells(Rand, 2) = R2(i, 2) And Not D0.exists(Rand) Then
R2.Cells(i, 2).Offset(0, 1) = R1(Rand, 1)
D0.Add Rand, Rand
Exit For
End If
Rand = (Rand Mod R1.Rows.Count) + 1
Next j
Next i
End Sub
The idea is to check the people skill list starting from a random point and making sure a key is not used twice.
EDIT:
According to your comment I assume a "people / skill" can then be assigned more than once as there are 7000+ customers ?
Code below randomly assign with a fairly good distribution 1500 peoples to 7000 customers in +/- 1 second.
Have a try and see if you can adapt it to your project.
Option Explicit
Sub Assign()
Application.ScreenUpdating = False
Dim Start: Start = Timer
Randomize
Range("C2:C99999").ClearContents
Dim D1 As Object
Dim R1 As Range: Set R1 = Range("L2", Range("M" & Rows.Count).End(xlUp))
Dim R2 As Range: Set R2 = Range("A2", Range("B" & Rows.Count).End(xlUp))
Dim T1: T1 = R1
Dim T2: T2 = R2
Dim T3()
Dim a As Integer: a = 1
Dim i As Integer, j As Integer, k As Integer, Rnd_Val As Integer, j_loop As Integer
For i = 1 To (Int(R2.Rows.Count / R1.Rows.Count) + 1)
Set D1 = CreateObject("scripting.dictionary")
For j = (R1.Rows.Count * i - R1.Rows.Count + 1) To R1.Rows.Count * i
ReDim Preserve T3(1 To j)
Rnd_Val = Int(Rnd * R1.Rows.Count + 1)
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) And Not D1.exists(Rnd_Val) And T3(j) = "" Then
T3(j) = T1(Rnd_Val, 1)
D1.Add Rnd_Val, Rnd_Val
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
If T3(j) = "" Then
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) Then
T3(j) = T1(Rnd_Val, 1)
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
End If
a = a + 1
If a > R2.Rows.Count Then GoTo EndLoop
Next j
Set D1 = Nothing
Next i
EndLoop:
Range("C2").Resize(UBound(T3), 1) = Application.Transpose(T3)
Debug.Print Timer - Start
Application.ScreenUpdating = True
End Sub
I have written some code that reads a spreadsheet that is filled with procedures that will be carried out by workers and divides them into "shifts" based on the duration of each activity so that preparation for certain steps can be made before.
I am looking for some help, as if someone inputs text that is not an integer (a note or something) into the "duration" tab, (which is stored as "X" in this code) the macro stops prematurely.
I was thinking I could use an if statement to check this, perhaps the "IsNumeric()" function, but it would not run and I knew I was not doing it correctly.
Private Sub CommandButton1_Click()
'define variables
Dim duration As Integer, n As Long, i As Integer, x As Integer, m As Long
Dim toolRange As Range, partRange As Range, perRange As Range, workRange As Range, ppeRange As Range
n = 3 'indicates row
m = 3 'concatenation counter
duration = 0 'duration counter
x = 0 'duration placeholder
For i = 1 To 100 'Assumed max 50 shifts (This can be changed or solved with more code, but should be set higher than predicted # of shifts)
duration = 0 'resets duration for next count
While duration < Worksheets("Shifts").Cells(6, "K").Value 'shift length can be altered
x = Worksheets("SR060-SR070").Cells(n, "F").Value
duration = duration + x 'adds duration until it is over 320
n = n + 1
Wend
With Worksheets("SR060-SR070")
Set toolRange = .Range(.Cells(m, "H"), .Cells(n, "H")) 'creates tool range
End With
With Worksheets("SR060-SR070")
Set partRange = .Range(.Cells(m, "I"), .Cells(n, "I")) 'creates part range
End With
With Worksheets("SR060-SR070")
Set perRange = .Range(.Cells(m, "E"), .Cells(n, "E")) 'creates per range
End With
With Worksheets("SR060-SR070")
Set workRange = .Range(.Cells(m, "P"), .Cells(n, "P")) 'creates permit range
End With
With Worksheets("SR060-SR070")
Set ppeRange = .Range(.Cells(m, "Q"), .Cells(n, "Q")) 'creates ppe range
End With
Worksheets("Shifts").Cells(i + 1, 1).Value = i 'creates shift
Worksheets("Shifts").Cells(i + 1, 2).Value = Application.Max(perRange) 'creates max per
Worksheets("Shifts").Cells(i + 1, 3).Value = duration 'creates duration
'Worksheets("Shifts").Cells(i + 1, 4).Value = ConcatenateAllCellValuesInRange(toolRange) 'inputs tools
Worksheets("Shifts").Cells(i + 1, 4).Value = ConcatUniq(toolRange, " ") 'inputs tools
'Worksheets("Shifts").Cells(i + 1, 5).Value = ConcatenateAllCellValuesInRange(partRange) 'inputs parts
Worksheets("Shifts").Cells(i + 1, 5).Value = ConcatUniq(partRange, " ") 'inputs parts
'Worksheets("Shifts").Cells(i + 1, 6).Value = ConcatenateAllCellValuesInRange(workRange) 'inputs permits
Worksheets("Shifts").Cells(i + 1, 6).Value = ConcatUniq(workRange, " ") 'inputs permits
'Worksheets("Shifts").Cells(i + 1, 7).Value = ConcatenateAllCellValuesInRange(ppeRange) 'inputs ppe
Worksheets("Shifts").Cells(i + 1, 7).Value = ConcatUniq(ppeRange, " ") 'inputs ppe
m = n 'Allows it to segement down page
Next i 'goes to next shift
End Sub
'Concatenate function
Function ConcatUniq(ByRef rng As Range, _
ByVal myJoin As String) As String
Dim r As Range
Static dic As Object
If dic Is Nothing Then _
Set dic = CreateObject("Scripting.Dictionary")
For Each r In rng
dic(r.Value) = Empty
Next
ConcatUniq = Join$(dic.keys, myJoin)
dic.RemoveAll
End Function
You could use the Val function to get the numeric part of a string. Val will also return 0 if the value is not numeric or empty string. You could combine this with IsNumeric in your While condition.
Dim vVal As Variant
Dim nVal As Long
vVal = Worksheets("Shifts").Cells(6, "K").Value
nVal = Val(vVal)
While duration < nVal && IsNumeric(vVal)
...
Wend
References:
Val Function - VBA
IsNumeric Function - VBA