Vbscript loop, if then issue - vbscript

I need some assistance. I am new to vbscript and I have a problem/question.
I am trying to give an end user the ability to start a program over.
I have done research on MSDN and googled various other sites that involve tutorials based on if then statements, subroutines, functions and do,while,until loops
all the loop tutorials or explanations have a program looping through numbers and string lengths. I have developed a common stock transaction program:
'Stock Transaction Program
Option Explicit
Dim stockPrice, commission, stocksBought, stockCommission, stockTotal, totalCost, tryAgain
Wscript.StdOut.Write "Stock price: "
stockPrice = CDbl(Wscript.StdIn.ReadLine)
Wscript.StdOut.Write "Number of stocks bought: "
stocksBought = CDbl(Wscript.StdIn.ReadLine)
Wscript.StdOut.Write "Stock Commission percentage in whole number (i.e 2 for 2%): "
commission = CDbl(Wscript.StdIn.ReadLine)
stockTotal = stockPrice * stocksBought
stockCommission = commission * stockTotal / 100
totalCost = stockCommission + stockTotal
Wscript.StdOut.WriteLine "You payed a total commission of $" & stockCommission & " on the stocks you bought."
Wscript.StdOut.WriteLine "Your total price for you purchasing " & stocksBought & " stocks is $" & totalCost & "."
After this program concludes, I would to give the end user an option to evaluate another stock price..etc.
Wscript.Stdout.Writeline "Would you evaluate another stock price? (i.e y or n): "
tryAgain = lcase(wscript.stdin.readline)
My logic assumes that you would now proceed with an if statement of some kind that basically says: that if tryAgain equals "y" then proceed back to the top, if "n" then exit program with a thank you conclusion, if invalid character then state that the end user entered an invalid response, allowing them the oppurtunity to try again.
I couldn't figure it out. functions and subroutines need arguments (i assume) and subroutines do not give data output. functions do but this code doesnt classify. I was hoping that their was a syntax that would allow the program to start over. I think a loop of some kind is probably the answer but i dont have the knowledge or the experience.
Is their anyone that can assist me???
Thanks

This could be one of the simplest solutions.
Option Explicit
Dim stockPrice, .... , tryAgain
Do
'....
' your stocks code
'....
Wscript.Stdout.Writeline "Would you evaluate another stock price? (i.e y or n): "
tryAgain = lcase(wscript.stdin.readline)
Loop While tryAgain="y"

Related

VBS script random and switches

In the program below r is initialized as a rounded random number and the user is prompted to guess. If the user guesses correctly there is one prompt Else there is another prompt. The code looks right but when ran the Else case is chosen whether the user got the number right or not. Please help I have read over it so many times that it hurts.
Set WshShell = WScript.CreateObject("WScript.Shell")
'This script is designed to create a random number, and have a user guess the number
'If the user guesses the number incorrectly, negatively impact the users system
'if the user guess the number correctly, do nothing
dim InputValue
dim UserInput
'create a random number
dim r
randomize
r = int(rnd * 10)+1
'Allow the user to guess what number is correct
Input = inputbox ("Choose a number from one to ten, and choose wisely ;)", "Type a number.")
InputValue = Input
'Provide the user with feedback as to what his/her choice was and what the number actually was.
UserInput = "You typed " & InputValue & "." & " The number was " & r & "."
'echo the random generated number for test purposes
WScript.Echo r
Select Case InputValue
Case r
WScript.Echo "No action"
Case Else
WScript.Echo "Negative Action"
End Select
The issue is that InputValue is a String type because that's what's returned by the InputBox function and r is an Integer, so when you compare InputValue to r, you're comparing a string to an integer, i.e. apples to oranges.
Proof of concept:
Dim x
x = "5"
Dim y
y = 5
Select Case x
Case y
MsgBox "Yes"
Case Else
MsgBox "No" 'this is what happens.
End select
VBScript is not a strongly-typed language, i.e. it does not know about types really at all -- well, it kind of knows. It treats every variable as one type called a "variant" which itself can then have an affinity to a more specific type but in a very confusing and error-prone way. I'd say you should read this to learn more about it.
You can get into a lot of trouble with this unless you always make sure you know what "types" you're working with.
Try changing it to this:
InputValue = CInt(Input)
Now you're converting the "string" into an "integer" (the variables are both still actually "variants" but they have the same underlying affinity to integer). However, you want to be careful because someone might input a value that is not able to be converted to an integer, e.g. hello, and thus you'll get an error on this line. You will need to do some error checking first before converting it.

vbscript Execute: exit external For

Execute in vbscript is used to parse strings into inline instructions. However, I can't use it to break For loops. The following won't work:
For i = 1 To 10
msgbox i
Execute("Exit For")
Next
Does somebody know any workaround for it to work? Or any way for Exit Sub/Exit Function work? I tried ExecuteGlobal, but it also raises "invalid exit instruction" error.
I used it as a form of "import" throughout my code and it is going to be time consuming to implement another form of import all over again, so I am searching for a way to make it work before considering to change the project.
EDIT: more examples
In short, I tried to do a partial override of a semi-abstract method, but can't use Exit For against a For outside the Execute block.
Dim names_array 'this array will be populated in another Sub
'this method will loop though all elements of an array and insert some items into a database...
'but the method does not know (how to)/(if it will really) insert into the database!
'all it knows is: it has to loop though the array... and, if needed, finish earlier
'the insertion part will have to be described before running, like a 'partial override' of an abstract method
'that is because I know how part of the method must be, but the details will be diferent for each database
'I don't want to override every method entirely!
Sub insert_into_database
For i = 0 To UBound(names_array)
name = names_array(i)
Execute(core_op) 'here comes the core operation, it is what I override!
Next
End Sub
'for some databases, core_op will be simple:
core_op = "objRecordSet.Open ""INSERT INTO videos (title, date_time) VALUES ('"" & name & ""', Now)"", objConnection"
'for others, it may be complex:
core_op = "If name=""18+ only"" Then"
core_op = core_op + " MsgBox ""You tried to insert nasty things. System will now halt."""
core_op = core_op + " Exit For"
core_op = core_op + "Else"
core_op = core_op + " objRecordSet.Open ""INSERT INTO videos (title, date_time) VALUES ('"" & name & ""', Now)"", objConnection"
core_op = core_op + "End If"
'the string won't be loaded this way, it will come from an external file
'there are other methods that operate like this, but not all of them need Exit For
That is closer to my project. The reality is: the code for the overrides will come from an external file and will be stored in a dictionary.
Sorry if it seems a mess, that is the way I tried to make vbscript more java-like regarding reusability.
Exit statements are parts of compound statements (loops, routines) and must be 'compiled' in their contexts. So there is no workaround and you have to redesign your import strategy. Perhaps you should publish your current approach.
Update wrt comment (partial override of the method):
Use GetRef and pass "function pointers", or invest in some classes and send objects to the enclosing function.

Trying to make my own vbscript

I have been working on this vb script for around an hour trying to get it to work there is many skype spammer scipts but i want to make one that includes a random number generator my script is this i call it at the moment "Skype_randizer_mk1"
If anyone would be able to take a look at it it would be greatly appreciated.
When i was posting this the website said i had to indent this so it may look a little strange
The Delay variable is the amount of time it will take to enter another number
I don't mind if this program makes only numerical values that is what i intend for it to do
set shell = createobject ("wscript.shell")
dim max
dim min
dim delay
max = 100
min = 1
delay = 0.00000001
for i = 1 to 5
randomize
intnumber = int((max - min + 1) * rnd + min )
wscript.echo intnumber
Next
for b=1 to delay
shell.sendkeys (intnumber)
wscript.sleep(delay)
if not isnumeric(delay) then
wscript.quit
end if
msgbox "You have 5 seconds to get to your inputbox."
wscript.sleep ( 5000 )
Next
You have lots of problems with your code:-
You should ALWAYS declare your variables using Dim: e.g. Dim shell
You are missing a Next for one of your For loops
Line 10 doesn't make much sense. It says: for b=1 to delay, but delay = 0.00000001, so your loop will never run. Also, why does this section even need to loop? I think you probably just want an If/Then/Else
Line 11 should probably say shell.SendKeys, not strshell.sendkeys as this is an uninitialised variable
Line 13 is checking for a numeric delay value. How will this ever be anything other than numeric when you are assigning a value of 0.00000001 on line 4 and it never changes. As a result, you will not exit the script until the for loop on line 5 has executed 5 times.

Applescript Error "can't get end of"

I am trying my hand at Applescript and can't see anything wrong with this.
The Error I get is
error "Can’t get end of {button returned:\"OK\", text returned:\"3\"}." number -1728 from last insertion point of {button returned:"OK", text returned:"3"}
This is my code:
beep
set counter to 0
set tempX to 0
set temp to 0
set counting to 0
set stored to {0}
set input to "How many grades do you wish to enter?" as string
set str to display dialog input buttons {"NEXT"} default button "NEXT" default answer ""
repeat text returned of str times
counting = counting + 1
set grades to display dialog "GRADES: " default answer ""
set stored to grades
end repeat
set rep to the length of stored
repeat rep times
counter = counter + 1
set tempX to the ((end of stored) - counter) as number
set temp to temp + tempX
end repeat
set ln to the length of grades
set average to temp / ln
if text returned of str is 1 then
say "The Average of your grade is " & average using "Zarvox"
else
say "The Average of your grades is " & average using "Zarvox"
end if
get "AVERAGE: " & average
So, before I begin: I'd strongly recommend that you teach yourself how to use the Javascript interface to Apple Events, rather than the Applescript language itself. Applescript is a really weird language, and its quirks are largely unique; learning it is going to be frustrating, and won't help you learn other languages.
That being said, let's dive into your code:
set stored to {0}
This would start you out with one grade that's always present and set to zero. You probably want to just initialize this to an empty list:
set stored to {}
Next:
set grades to display dialog "GRADES: " default answer ""
This sets grades to a result object, not just the answer. What you probably want here is actually the text returned of the result:
set grades to text returned of (display dialog "GRADES: " default answer "")
(This is what's creating the really weird-looking object in your error message.)
Next, you overwrite stored with this result object:
set stored to grades
What you probably want here is to insert this element into the list. Because Applescript is a strange and obnoxious language, this is somewhat more cumbersome than you're thinking:
set stored to stored & {grades}
Finally, there's some logical issues with your averaging; you're adding the end of stored (that is, the last grade input) to the temp variable each time. A much simpler approach would be:
set temp to 0
repeat with n in stored
set temp to temp + n
end repeat
set average to sum / (count of stored)
With these changes all made, your script should work correctly.

VBA loop efficiency

I've used the answers found in the site a TON of times, but this is my first post.
Is it more efficient to perform a for loop inside a function or sub or to just send the incremented value of the loop into the function or sub as an argument?
I am importing some text data files into Excel, parsing out the various fields, and then splitting some of the fields into individual characters. One file I am using is a list of doctors. I have name, address, phone, DEA number, NPI, etc.
When checking the DEA number, I have a sub that receives the line number to be checked that splits the DEA into its individual digits, perform checking on these digits one at a time and then modify another field with the status of that DEA. This status cell will be colored red if it contains anything but the word "GOOD". Also, I am coloring the individual digit that is bad, if applicable.
This one sub is doing a lot and I could probably break it up a little, but there aren't any other places in the doctor file that I am performing this exact step, so I figured I should keep it like it is.
Anyways, the real question is whether I should send the line number into the sub or should I just call the sub and have the sub calculate the number of lines and do the checking. In the first case, I will call the sub a number of times equal to the number of lines in the doctor file. In the second, I will call the sub once and the sub contains the for loop for each line. Which is usually more efficient.
Apologies if I seem redundant. I train some complex software and that sort of thing leaks into other areas of life sometimes.
EDIT: I tried to add this into a comment but have insufficient experience posting here. Apologies if I violate some rule for this...
Here is the code I use currently to call the sub:
'Use the Doctor Last Name as the number of rows count
Dim numRows As Integer
numRows = Application.CountA(Sheets("DoctorDEA").Range("m:m"))
'lineCtr is the Line Counter used to iterate the FOR loops
Dim lineCtr As Integer
lineCtr = 1
'Call DEACHecking and DisplayIssues Subs
For lineCtr = 1 To numRows - 1
DEAChecking (lineCtr)
DisplayIssues (lineCtr)
Next lineCtr
My questions is this: Would it be better to just call DEAChecking with no arguments and just have DEAChecking calculate the line numbers and then use the FOR loop or to leave it as is?
This question is too broad right now to be answered effectively. So am just offering a small insight that might help you structure your program.
Typically the most efficient code is the one where all the variables are as local as possible. If inside a loop you are using globals, or calling other functions it is going to be much worse than performing all the calculation with local variables.
If you want to test each, and time them, you can use a timer. If you have a major gap, you will be able to catch it. If not, you will have your answer with no significant difference as far as processing time.
You can either use this and call your sub from TimerTest, or simply Call TimerStart at the beginning of your code and TimerStop at the end.
Run some code with the timer
Log the result
Repeat and compare
HH:MM:SS:00 format
Timer Code:
Public strStartTime As String
Public strEndTime As String
Public startTime As Date
Public endTime As Date
Sub timeTest()
Call TimerStart
'INSERT CALL TO YOUR SUB HERE
Call TimerStop
End Sub
Sub TimerStart()
startTime = Now
End Sub
Sub TimerStop()
endTime = Now
'Waited until the timer stopped to perform any additional code, such as formatting the time
Dim TotalTime As String
strStartTime = Format(startTime, "hh:mm:ss:" & Right(Format(Timer, "#0.00"), 2))
strEndTime = Format(endTime, "hh:mm:ss:" & Right(Format(Timer, "#0.00"), 2))
TotalTime = Format(endTime - startTime, "hh:mm:ss:" & Right(Format(Timer, "#0.00"), 2))
MsgBox (" Start: " & strStartTime & vbNewLine & _
" End: " & strEndTime & vbNewLine & _
"Total Time : " & TotalTime)
End Sub
Credit: #Nick Dandoulakis for timer formatting in his answer here: Providing this solution to show clock time with accuracy of less than a second.

Resources