Here is my code:
import openpyxl
wb = openpyxl.load_workbook("Bok1.xlsx", data_only=True)
ws = wb["Blad1"]
n = 0
for row in ws['A1:A100']:
for cell in row:
if cell.value == "Konto":
for hej in range(13):
n+=1
konto = cell.offset(row=n).value
if konto == None or isinstance(konto, str) == True:
pass
else:
if konto == 306888 or konto == 306889:
#derp = input("derpderpderp?: ")
#if derp == "y":
if konto == 306888 or konto == 306889:
kst = cell.offset(row=n, column = 1).value
proj = cell.offset(row=n, column = 2).value
vht = cell.offset(row=n, column = 3).value
motp = cell.offset(row=n, column = 4).value
fin = cell.offset(row=n, column = 5).value
text = cell.offset(row=n, column = 8).value
belopp = cell.offset(row=n, column = 9).value
print(konto)
print(kst)
print(proj)
print(vht)
print(motp)
As you can see by the # in the code, I have a input that is "dependent" on a loop. How could I write this code so that it is not looping over and asking for the input for every iteration?
What I would do is to keep a counter:
n = 0
cnt=1 # counter
for row in ws['A1:A100']:
# continue with your code
Then, when you get to your input :
if cnt==1:
derp = input("derpderpderp?: ")
cnt += 1
if derp == "y":
#continue with your code
This way, you ensure that your input is taken only on the first go.
Related
The following code I have Will paste a value code of "01" to a cell and then skip 4 rows continuously, until reaching the end of count within the for loop. I want to run a similar loop for "02", but rather than "Step" (skip) 4 rows, I would like it to insert the value in 6 consecutive rows within the same column and then skip 3 rows continuously until reaching the end of count. I am 2 weeks new to vba, so I hope I am explaining this correctly.
Dim i As Long
If Sheet3.Range("C22").Value = "01" Then
For i = 3 To 202 Step 4
ActiveWorkbook.Sheets("CrewEntries").Cells(i, 6).Value = _
ActiveWorkbook.Sheets("MonData").Cells(22, 5).Value
Next i
ElseIf Sheet3.Range("C22").Value = "02" Then
For i = 3 To 152
ActiveWorkbook.Sheets("CrewEntries").Cells(i, 6).Value = _
ActiveWorkbook.Sheets("MonData").Cells(22, 5).Value
Next i
End If
Maybe like this:
Dim i As Long, v
v = ActiveWorkbook.Sheets("MonData").Cells(22, 5).Value
If Sheet3.Range("C22").Value = "01" Then
For i = 3 To 202 Step 4
ActiveWorkbook.Sheets("CrewEntries").Cells(i, 6).Value = v
Next i
ElseIf Sheet3.Range("C22").Value = "02" Then
For i = 3 To 152 Step 9 '6 filled + 3 empty = 9
ActiveWorkbook.Sheets("CrewEntries").Cells(i, 6).Value = v
Next i
End If
For such a kind of question, I would advise a while-loop, as in this piece of pseudo-code:
dim condition as boolean
dim loop_step, interesting_value as integer
condition = true
loop_step = 1 'just in order to be sure that it never is 0, this might create an infinite loop
interesting_value = 0 ' or some other initialisation value
while condition do
if <some_first_condition>
then
do_first_thing(interesting_value, ...)
loop_step = 3
else
do_second_thing(interesting_value, ...)
loop_step = 6
end if
interesting_value = interesting_value + loop_step
if <some_other_condition> then condition = false
Wend
Sub EarningCode()
Dim CpID As String
Dim i As Long
Dim p As Long
CpID = ActiveWorkbook.Sheets("MonData").Cells(22, 3).Value
For i = 3 To 452
If p = 9 Then
p = 1
Else
p = p + 1
End If
If p < 7 Then
ThisWorkbook.Worksheets("CrewEntries").Cells(i, 4).Value = "02"
End If
Next i
End Sub
I have a userform with 7 combo boxes that are used to search data from the worksheet. I intend to present column 6(mass) and 8(index) as ranges i.e. for mass: 0.007-0.1; 0.11-2.5; 0.251-0.5 etc. The other 5 combo boxes are just absolute values (not range).I'm attempting to loop through the cells in the data sheet(shD) and whenever the row matches matches all selections made on the userform; then the entire row is copied to the results sheet(shR). The user may leave some of the combo boxes blank, but they should still be able to get results. What the code is doing now is may be say in the time combobox(cbInj) I selected say 15 seconds; the code will include 20 seconds which does not match the 15sec on the combo box. Here is my code;
'combo boxes variable definition, in order to compact and make the code easy to be understood:
Set cbPr = User_search.Cbx_Project_code
Set cbTr = User_search.Cbx_TrueNOC
Set cbDn = User_search.Cbx_DNAmass
Set cbK = User_search.Cbx_Kit
Set cbQ = User_search.Cbx_QIndex
Set cbInj = User_search.Cbx_Injection_time
Set cbInstr = User_search.Cbx_Instrument
'Check selection for mass and present it as a range
If Len(cbDn.Value) > 0 Then
arrDn = Split(cbDn.Value, "-")
mnDn = CDbl(arrDn(0))
mxDn = CDbl(arrDn(1))
End If
'checkfor Index if selected and present it as a range
If Len(cbQ.Value) > 0 Then
arrQ = Split(cbQ.Value, "-")
mnQ = CVar(arrQ(0))
mxQ = CVar(arrQ(1))
End If
'count the total rows on Data
totD = shD.Range("B" & Rows.Count).End(xlUp).Row 'last row of "Data" sheet
For i = 5 To totD
vDn = shD.Cells(i, 6).Value
vQ = shD.Cells(i, 8).Value
If (Trim(shD.Cells(i, 2)) = Trim(cbPr.Value) Or cbPr.Value = "") And _
(Trim(shD.Cells(i, 5)) = Trim(cbTr.Value) Or cbTr.Value = "") And _
vDn > mnDn And vDn <= mxDn Or cbDn.Value = "" And _
(Trim(shD.Cells(i, 7)) = Trim(cbK.Value) Or cbK.Value = "") And _
vQ > mnQ And vQ <= mxQ Or cbQ.Value = "" And _
(Trim(shD.Cells(i, 9)) = Trim(cbInj.Value) Or cbInj.Value = "") And _
(Trim(shD.Cells(i, 10)) = Trim(cbInstr.Value) Or cbInstr.Value = "") Then
totR = shR.Cells(Rows.Count, 1).End(xlUp).Row
shD.Rows(i).EntireRow.Copy Destination:=shR.Cells(totR + 1, 1)
End If
Next i
Slight logic problem in your "range" tests - eg:
vQ > mnQ And vQ <= mxQ Or cbQ.Value = "" And _
should be
((vQ > mnQ And vQ <= mxQ) Or cbQ.Value = "") And _
I would do something like this. Individual tests are faster, since there's no need to continue checking after any failed test
Sub Tester()
Dim cbPr, cbTr, cbDn, cbk, cbQ, cbInj, cbInstr 'all variants
Dim rw As Range, isMatch As Boolean, arrCrit
'get combo boxes values
cbPr = Trim(User_search.Cbx_Project_code.Value)
cbTr = Trim(User_search.Cbx_TrueNOC.Value)
cbDn = Trim(User_search.Cbx_DNAmass.Value)
If Len(cbDn) > 0 Then cbDn = Split(cbDn, "-") 'convert to array
cbk = Trim(User_search.Cbx_Kit.Value)
cbQ = Trim(User_search.Cbx_QIndex.Value)
If Len(cbQ) > 0 Then cbDn = Split(cbQ, "-") 'convert to array
cbInj = Trim(User_search.Cbx_Injection_time.Value)
cbInstr = Trim(User_search.Cbx_Instrument.Value)
arrCrit = Array(2, cbPr, 5, cbTr, 6, cbDn, 7, cbk, 8, cbQ, 9, cbInj, 10, cbInstr)
For i = 5 To shD.Range("B" & Rows.Count).End(xlUp).Row
Set rw = shD.Rows(i)
For n = LBound(arrCrit) To UBound(arrCrit) - 1 Step 2
isMatch = CellIsMatch(rw.Cells(arrCrit(n)), arrCrit(n + 1))
If Not isMatch Then Exit For
Next n
If isMatch Then rw.Copy shR.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
Next i
End Sub
'Does a cell value match the supplied criteria?
' Criteria could be a range of two numeric values
Function CellIsMatch(cell As Range, crit) As Boolean
Dim v
v = cell.Value
If Len(v) > 0 Then
'is the criteria an array (range) ?
If TypeName(crit) Like "*()" Then
'assumes v is numeric
CellIsMatch = (v > CDbl(Trim(crit(0))) And _
v < CDbl(Trim(crit(1))))
Else
CellIsMatch = (Trim(v) = crit) Or Len(crit) = 0
End If
End If
End Function
I found this code to split a CSV file using python.
I need to split 3,000,000 record CSV file when the column A changes.
I also need to add 2 more fields to the table
Blank (add a comma next to each line).
Add a date in the last field, but it should ask me for the date.
Would someone be able to help me add 2 thing to this code.
A prompt to add more fields
A prompt what should be in the field
I am copying the code from the link included earlier
#!/usr/bin/env python3
import binascii
import csv
import os.path
import sys
from tkinter.filedialog import askopenfilename, askdirectory
from tkinter.simpledialog import askinteger
def split_csv_file(f, dst_dir, keyfunc):
csv_reader = csv.reader(f)
csv_writers = {}
for row in csv_reader:
k = keyfunc(row)
if k not in csv_writers:
csv_writers[k] = csv.writer(open(os.path.join(dst_dir, k),
mode='w', newline=''))
csv_writers[k].writerow(row)
def get_args_from_cli():
input_filename = sys.argv[1]
column = int(sys.argv[2])
dst_dir = sys.argv[3]
return (input_filename, column, dst_dir)
def get_args_from_gui():
input_filename = askopenfilename(
filetypes=(('CSV', '.csv'),),
title='Select CSV Input File')
column = askinteger('Choose Table Column', 'Table column')
dst_dir = askdirectory(title='Select Destination Directory')
return (input_filename, column, dst_dir)
if __name__ == '__main__':
if len(sys.argv) == 1:
input_filename, column, dst_dir = get_args_from_gui()
elif len(sys.argv) == 4:
input_filename, column, dst_dir = get_args_from_cli()
else:
raise Exception("Invalid number of arguments")
with open(input_filename, mode='r', newline='') as f:
split_csv_file(f, dst_dir, lambda r: r[column-1]+'.csv')
# if the column has funky values resulting in invalid filenames
# replace the line from above with:
# split_csv_file(f, dst_dir, lambda r: binascii.b2a_hex(r[column-1].encode('utf-8')).decode('utf-8')+'.csv')
Thank you
had it written in VBS
basename = "csv_split_"
hasHeader = True 'Change to False if there is no header.
argCnt = WScript.Arguments.Count
If argCnt < 1 Then
WScript.Echo "Drag a CSV over this script to edit it."
WScript.Quit
End If
flnm = WScript.Arguments.Item(0)
set fs = WScript.CreateObject("Scripting.FileSystemObject")
set cv = fs.OpenTextFile (WScript.Arguments.Item(0))
If Not fs.FileExists(flnm) Or LCase(fs.GetExtensionName(flnm)) <> "csv" Then
WScript.Echo "This script is meant for CSV only."
WScript.Quit
End If
fol = fs.GetParentFolderName(flnm)
customValue = InputBox("What should the last column contain?", "Column Info")
Set pat = New RegExp
pat.Global = True
pat.IgnoreCase = True
pat.Pattern = "^(""[^""]*""|[^,]*)?,"
recentCol = ""
csvCount = 1
header = ""
cnt = 0
While Not cv.AtEndOfStream
cnt = cnt + 1
row = cv.ReadLine
If Right(row,1) <> "," Then: comma = ",": Else: comma = "": End If
Set col1 = pat.Execute(row)
col = col1.Item(0).Value
sameFile = true
If recentCol <> "" Then
If col <> recentCol And cnt > 2 Then
csvCount = csvCount + 1
sameFile = false
End If
Else
header = row & comma & """Off Peak"",""Effective Date"""
Set csv = fs.OpenTextFile(fol & "\" & basename & csvcount & ".csv", 8, True)
End If
recentCol = col
If Not samefile Then
csv.close
Set csv = fs.OpenTextFile(fol & "\" & basename & csvcount & ".csv", 8, True)
End If
If hasHeader And (1 = cnt or Not samefile) Then
csv.WriteLine(header)
Else
csv.WriteLine(row & comma & ",""" & customValue & """")
End if
Wend
csv.Close
Works Great!
I scan a barcode into an ActiveX textbox. It selects the relevant case and performs the calculation/event depending on the barcode. Every code is connected to an event.
One out of 100+ scans is not correctly decoded to the computer. As such, it does not match a case and does not make the textbox value "". It then appends to every other scan entering into the textbox. Aka "15 - FT - R" might scan in as "15 - FT -R".
I need the code to recognize this as a non case and delete it.
Since the barcode scans each character one at a time, nothing is equal to a case until the barcode value has completely entered the textbox.
Is there any way to tell if the barcode info is done being scanned?
My biggest challenge is how to stop the rest of the text from entering the box once it does not match a case.
My next biggest challenge is setting variables.
Private Sub TextBox1_Change()
Dim ws As Worksheet, v, e, f, g, k, i4
Set ws = Worksheets("Sheet1")
v = TextBox1.Value
e = 0
f = 0
g = 0
k = 0
i4 = 0
Select Case v
Case "15 - FT - R": f = 5
e = 11
k = 2
g = "15 - FT - R"
Case "150 - FT - C": f = 30
e = 11
k = 2
g = "150 - FT - C"
Case "R Waste": f = 4
e = 9
k = 2
g = "R Waste"
Case "C Waste": f = 4
e = 10
k = 2
g = "C Waste"
Case "Accident - 4": k = 5
'other cases here....
End Select
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'g = name of the item being used for the time stamp
'k = Case Selection
'i4 = Count for Cutting Station 1 timestamp, row reference
If k = 2 Then
'Coating Station
'accidental scan references for coating
ws.Cells(4, 4) = f
ws.Cells(5, 4) = e
ws.Cells(f, e) = ws.Cells(f, e) + 1
'adds master roll
i4 = ws.Cells(4, 30)
'count function
Cells(i4, 25).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i4, 26).Value = g
'formatting timestamp
TextBox1.Activate
TextBox1.Value = ""
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'k = Case Selection
'i4 = Count for Cutting Station 1 timestamp, row reference
ElseIf k = 5 Then
'Accidental scan
f = ws.Cells(4, 4)
e = ws.Cells(5, 4)
ws.Cells(f, e) = ws.Cells(f, e) - 1
i4 = ws.Cells(4, 30)
'count function
Cells(i4, 25).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i4, 26).Value = "Accident"
'formatting timestamp
TextBox1.Activate
TextBox1.Value = ""
End If
End Sub
Set TextBox properties:
EnterKeyBehavior TRUE
Multiline TRUE
Use this in your VBA _Change call back:
If Not Right(Me.Scan.Value, 1) = vbLf Then Exit Sub
In essence, we're now just looking for the LF character after enabling the multiline capability of the textbox.
I want to build a survey using excel and vba. I have a table with questions and answers. As the survey starts, my code will list the answers by overwriting the checkboxes' labels on a form. I will fetch their answer and write them in a column by using True or False value of a checkbox.
Variable "aRow" is the number of the answers for each question. "lastAns" is the row number of the last answer. Depending on the number of the answer, some checkboxes will be hidden, shown. "CheckBox1" to "CheckBox4" are the names of the checkboxes.
The following code works, but it is too long and I want to have a better method to loop through the checkboxes and changing their labels each time. Please show me how to do it!
Thanks you so much!
`lastAns = Cells(qRow, 5).End(xlDown).Row + 1
aRow = lastAns - qRow
If aRow >= 1 Then
Me.CheckBox1.Visible = True
Me.CheckBox1.Caption = Cells(qRow, 5)
Else: Me.CheckBox1.Visible = False
End If
If aRow >= 2 Then
Me.CheckBox2.Visible = True
Me.CheckBox2.Caption = Cells(qRow + 1, 5)
Else: Me.CheckBox2.Visible = False
End If
If aRow >= 3 Then
Me.CheckBox3.Visible = True
Me.CheckBox3.Caption = Cells(qRow + 2, 5)
Else: Me.CheckBox3.Visible = False
End If
If aRow >= 4 Then
Me.CheckBox4.Visible = True
Me.CheckBox4.Caption = Cells(qRow + 3, 5)
Else: Me.CheckBox4.Visible = False
End If
.....SAME CODE CONTINUES TILL 7...`
As a follow up answer to my comment, here is what I think you are looking for:
arow = lastAns - qRow
Dim i As Long, ctl As Control
For i = 1 To 4
Set ctl = Me.Controls("CheckBox" & i)
If i <= arow Then
ctl.Visible = True
ctl.Caption = Cells(qRow + i - 1, 5)
Else
ctl.Visible = False
End If
Next i