validate international phone number in vb6 - vba

I want validate international phone number in vb6 without using regular expressions
only () + this characters and numeric are allowed and it should be below 20 digits.
What I have tried:
private sub txtPhoneNo_validate ( cancel As boolean)
if txtPhoneNo = "" then exit sub
if not Isnumeric(txtPhoneNo) then
msgbox "phone number shold be in numeric only"
Elseif len(txtPhoneNo) > 20
msgbox "phone number shold be in numeric only"
Exit sub
end if
end sub
I want to add international format for validation in my code and () + this are the character only allowed
mainly i want to validate this kind of numbers +44 779-345666 +44 (0)779345666 0779 345666 0208-3456667

The approach I would suggest, based upon your stated requirements, is to force the user to enter ONLY valid characters:
Option Explicit
Private Sub Form_Load()
txtPhoneNo.MaxLength = 20
End Sub
Private Sub txtPhoneNo_KeyPress(KeyAscii As Integer)
'allow only <backspace> <space> ( ) + - numeric
If Not (KeyAscii = 8 Or KeyAscii = 32 Or KeyAscii = 40 Or KeyAscii = 41 Or _
KeyAscii = 43 Or KeyAscii = 45 Or (KeyAscii >= 48 And KeyAscii <= 57)) Then
KeyAscii = 0
End If
End Sub
In summary, this code enforces a maximum length of 20 characters and discards the keystroke if the key is not a valid character.
This may be sufficient for your needs, but in reality it doesn't really validate the data. For example, the + could be entered anywhere in the textbox and still pass our validation. In other words, we are not completely enforcing the rules for international phone numbers. To do so would require much more code or the use of Regular Expressions.

The following answer ensures no more than "20 digits" are included, not just characters. It also ensures that '+' can only be in the leading position, "-" and " " cannot be in the leading position. While other solutions could be valid, if you wanted to keep with the _Validate() event, or if you want other checks than the basic ones, such as limiting '+' to only the beginning, this might be of use.
Private Sub txtPhoneNo_Validate(ByRef Cancel As Boolean)
Const MaxLength As Long = 20
Dim ANI As String, Cleaned As String
ANI = txtPhoneNo.Text
If ANI = "" Then Exit Sub
Dim I As Long, C As String
For I = 1 To Len(ANI)
C = Mid(ANI, I, 1)
If IsNumeric(C) Then
Cleaned = Cleaned & C
ElseIf C = "(" Or C = ")" Or (I <> 1 And (C = " " Or C = "-")) Or (I = 1 And C = "+") Then
' don't count these in count
Else
MsgBox "Phone Number should be contain only numbers, parenthesis, a leading plus, and spaces."
Cancel = True
Exit Sub
End If
Next
If Len(Cleaned) > MaxLength Then
MsgBox "Phone Number should contain at most 20 digits (provided: " & Len(Cleaned) & ")."
Cancel = True
Exit Sub
End If
End Sub

Use Regular Expressions from VB6. There are plenty of regex patterns for international phone numbers out there. Use work done and verified by others.

Related

How do I compare values in VBA?

I have this Sub. It is activated when pressing a button on a user form and is used to count one entry up. I have the total amount of entries in this data base stored in A1. There is another button used to count one entry down, it works just fine. They both have checks so they don't load entries that don't exist. Somehow this one doesn't work.
Private Sub ButtonRight_Click()
MsgBox TextBoxID.Value
MsgBox Cells(1, 1).Value
MsgBox (TextBoxID.Value < Cells(1, 1).Value)
If TextBoxID.Value < Cells(1, 1).Value Then
LoadEntry (TextBoxID.Value + 1)
End If
End Sub
The LoadEntry Sub is used in other places as well and it works. I have this output stuff with MsgBox for debugging. It gives the outputs 1, 2, false. So (1 < 2) = false.
For comparison here is the other one which works:
Private Sub ButtonLeft_Click()
If TextBoxID.Value > 1 Then
LoadEntry (TextBoxID.Value - 1)
End If
End Sub
The problem is implicit conversions.
Strings are compared as text, so "10" is smaller than "2" because it sorts alphabetically as such.
Debug.Print "10" > "2" ' output: False
The value of a TextBox control is always a String; in order to treat it as a numeric value you must first convert it to a numeric value - but only if it's legal to do so (e.g. "ABC" has no equivalent numeric value).
Moreover, a cell's value is a Variant that may contain a number or another value that can (will) correctly but implicitly convert to a numeric value, but it could also be a Variant/Error (e.g. #N/A, or #VALUE! errors) that will throw a type mismatch error every time you try to compare it to anything (other than another Variant/Error value), so the cell's value should also be validated and explicitly converted before it's compared:
Dim rawValue As String
rawValue = TextBoxID.Value
If IsNumeric(rawValue) Then
Dim numValue As Double
numValue = CDbl(rawValue)
Dim cellValue As Variant
cellValue = ActiveSheet.Cells(1, 1).Value
If IsNumeric(cellValue) Then
If numValue < CDbl(cellValue) Then
LoadEntry numValue + 1
End If
End If
End If
Note that unqualified, Cells is implicitly referring to whatever the ActiveSheet happens to be - if that isn't the intent, consider qualifying that member call with an explicit Worksheet object, e.g. Sheet1.Cells(1, 1). If it is intentional, consider qualifying it with ActiveSheet so that the code says what it does, and does what it says.
Comparing values of different types in VBA is not a simple task, the result of the comparison depends on the types of variables, the possibility of conversion to a number, etc. Variant variables are compared differently than "non-Variant" variables. See https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/comparison-operators
According to the documentation, the Value property of the TextBox object has a base type Variant (see https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/value-property-microsoft-forms).
Therefore, the result of comparing Variant/String (TextBox.Value with String) and Variant/Double (Cell.Value with number) - TextBox.Value is always larger than Cell.Value:
Private Sub CommandButton1_Click()
TextBox1.Value = "123"
[A1].Value = 9999
Debug.Print "TextBox1.Value = " & TextBox1.Value & ", Type is " & TypeName(TextBox1.Value)
Debug.Print "[A1].Value = " & [A1].Value & ", Type is "; TypeName([A1].Value)
Debug.Print "TextBox1.Value > [A1].Value : (" & TextBox1.Value & " > " & [A1].Value & ") is " & (TextBox1.Value > [A1].Value)
Me.Hide
End Sub
'Output:
'TextBox1.Value = 123, Type is String
'[A1].Value = 9999, Type is Double
'TextBox1.Value > [A1].Value : (123 > 9999) is True
Therefore, it is advisable before comparing:
reduce the types of compared values to one;
to handle errors of type conversion
Simple way is to use Val() function https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/val-function
Private Sub ButtonRight_Click()
If Val(TextBoxID.Value) < Val(Cells(1, 1).Value) Then
LoadEntry (TextBoxID.Value + 1)
End If
End Sub
Also for this purpose I propose to create a function:
Function getNumDef(v As Variant, Optional defV As Long = -1) As Long
getNumDef = defV 'inintially getNumDef set as defaul value
On Error Resume Next
getNumDef = CLng(v) ' if error occurs, getNumDef value remains defV
End Function
It can be applied in the following way:
Private Sub ButtonRight_Click()
Dim TBV as Long, CV as Long
TBV = getNumDef(TextBoxID.Value) 'Type conversion and error handling
CV = getNumDef(Cells(1, 1).Value) 'Type conversion and error handling
If TBV < 0 Or CV < 0 Then
MsgBox "Some of the values are not numeric or less than 0" _
& vbCrLf & "Check the raw data", vbCritical + vbOKOnly, "Sub ButtonRight_Click()"
Else
If TBV < CV Then
'The parentheses in `LoadEntry (TextBoxID.Value + 1)` are syntax sugar,
' i.e. the argument `TextBoxID.Value + 1` in parentheses is passed as ByVal.
'If the argument without (), i.e. `LoadEntry TextBoxID.Value + 1`,
'it is passed as described in the Sub definition or the default ByRef
LoadEntry TextBoxID.Value + 1
End If
End If
End Sub

Storing string then displaying it with a label box

I am trying to store the string from an input box and then display it with dashes in the lblbox for a hangman game for a class.
These are the tasks that I am struggling with:
edit the program to allow a Secret Word of any length.
the program will allow the ‘guesser’ to guess 2 times the length of the word. As an example, the word ‘code’ will allow 8 total guesses.
As the user guesses at letters contained in the word the program will:
Count the number of attempts the user has completed.
Replace the appropriate dash (-) with the correct letter, if the correct letter has been guessed.
When all the letters have been guessed correctly all the dashes (-) should be replaced with the appropriate letters, and a message box should appear stating “Great Job playing Hangman.!”
If the user is unable to guess the correct word in the amount of guesses allowed; the dashes (-) should be replaced with GAME OVER! and a message box should appear stating “Sorry the correct word was________”
2 bonus points will be awarded for displaying all incorrect letters guess in a 3rd label control.
4 more additional bonus points will be awarded for not allowing, or counting a user who guesses the same incorrect letter twice.
Here is my code:
Dim strSecretWord As String
Dim strLetterGuessed As String
Dim blnDashReplaced As Boolean
Dim intNumberOfRemainingGuesses As Integer = 10
Dim intNumofGuesses As Integer = 0
lblSecretWord.Text = ""
lblNumberOfAttempts.Text = ""
'start game and have 1st user input a 5 letter word that 2nd player needs to guess
strSecretWord = InputBox("Please input a 5 letter word for user to guess:", "Please input secret word.").ToUpper
'displays five dashes for the secret word
lblSecretWord.Text = lblSecretWord.Text & "-----"
'guessing player recieves inputbox to make letter guesses
MessageBox.Show("The length of the word is 5 letters, you will be given 10 guesses", "10 guesses", MessageBoxButtons.OK)
MessageBox.Show("Player who gets to guess, BE READY!", "Good Luck Guessing", MessageBoxButtons.OK)
'Counts number of attempts player gets (10) and replaces dashes with guessed letter if correct
'If guessed letter was incorrect, user loses a turn
For intNumberofGuesses = 1 To 10
strLetterGuessed = InputBox("Please guess a letter:", "Letter Guess").ToUpper
'Uses an IntIndex counter of 0 to 4 to execute 5 times (5 dashes)
'Also uses the value of intIndex to check each of the 5 locations of the strSecretWord
For intIndex As Integer = 0 To 4
'if the user has guessed a correct letter then remove a dash and insert the correct letter guessed
If strSecretWord.Substring(intIndex, 1) = strLetterGuessed Then
lblSecretWord.Text = lblSecretWord.Text.Remove(intIndex, 1)
lblSecretWord.Text = lblSecretWord.Text.Insert(intIndex, strLetterGuessed)
blnDashReplaced = True
End If
Next intIndex
'If the user guessed a correct letter on their last guess the blnDashReplaced is set and the true condition of the If statement is executed
If blnDashReplaced = True Then
'if there are no more dashes, and the game has been solved.
If lblSecretWord.Text.Contains("-") = False Then
MessageBox.Show("Great Job playign Hangman!", "Game Over", MessageBoxButtons.OK)
lblRemainingNumberOfAttempts.Text = ""
lblNumberOfAttempts.Text = ""
Exit Sub
Else
blnDashReplaced = False
End If
Else
End If
lblNumberOfAttempts.Text = intNumberofGuesses
intNumberOfRemainingGuesses = intNumberOfRemainingGuesses - 1
lblRemainingNumberOfAttempts.Text = intNumberOfRemainingGuesses
Next
lblSecretWord.Text = "GAME OVER!"
MessageBox.Show("Better luck next time. Sorry the correct word was " & strSecretWord & ".", "You Lost", MessageBoxButtons.OK)
lblRemainingNumberOfAttempts.Text = ""
lblNumberOfAttempts.Text = ""
I added a list box to keep the guessed letters. Other comments and explanations in line.
Public Class Form3
'Move this to a class level variable so it can be seen by
'all the methods in the class
Private strSecretWord As String
Private Sub btnStartGame_Click(sender As Object, e As EventArgs) Handles btnStartGame.Click
Dim strLetterGuessed As String
Dim blnDashReplaced As Boolean
Dim intNumberOfRemainingGuesses As Integer
Dim intNumofGuesses As Integer = 0
'Display correct number of dashes
Dim numberOfDashes As Integer = strSecretWord.Length
'Create a string with correct number of dashes
'This uses and overload of the String constructor that takes a Char and an integer
'as arguments and returns a string with that character repeated that number
'of times. The lower case c following "-" indicates that - is a Char.
Dim TotalNumofGuesses = numberOfDashes * 2
lblRemainingNumberOfAttempts.Text = TotalNumofGuesses.ToString
intNumberOfRemainingGuesses = TotalNumofGuesses
Dim dashString As String = New String("-"c, numberOfDashes)
'displays the dashes
lblSecretWord.Text = dashString
'guessing player recieves inputbox to make letter guesses
'You can use an Interpolated string to display variables in line surrounded by { }.
'In older versions of VB String.Format() will yield the same result.
MessageBox.Show($"The length of the word is {numberOfDashes} letters, you will be given {TotalNumofGuesses} guesses", $"{TotalNumofGuesses} guesses", MessageBoxButtons.OK)
MessageBox.Show("Player who gets to guess, BE READY!", "Good Luck Guessing", MessageBoxButtons.OK)
'Counts number of attempts player gets and replaces dashes with guessed letter if correct
'If guessed letter was incorrect, user loses a turn
For counter = 1 To TotalNumofGuesses
strLetterGuessed = InputBox("Please guess a letter:", "Letter Guess").ToUpper
'If lstLettersGuessed.Contains(strLetterGuessed) Then
If lbxLettersGuessed.Items.Contains(strLetterGuessed) Then
MessageBox.Show($"{strLetterGuessed} has already been guessed.", "Try Again")
'need to do this so they are not cheated out of a guess
TotalNumofGuesses += 1
Continue For 'Moves to the next iteration of the For
End If
lbxLettersGuessed.Items.Add(strLetterGuessed)
'lstLettersGuessed.Add(strLetterGuessed)
'Uses an IntIndex counter of 0 to 4 to execute 5 times (5 dashes)
'Also uses the value of intIndex to check each of the 5 locations of the strSecretWord
For intIndex As Integer = 0 To numberOfDashes - 1
'if the user has guessed a correct letter then remove a dash and insert the correct letter guessed
If strSecretWord.Substring(intIndex, 1) = strLetterGuessed Then
lblSecretWord.Text = lblSecretWord.Text.Remove(intIndex, 1)
lblSecretWord.Text = lblSecretWord.Text.Insert(intIndex, strLetterGuessed)
blnDashReplaced = True
End If
Next intIndex
'If the user guessed a correct letter on their last guess the blnDashReplaced is set and the true condition of the If statement is executed
If blnDashReplaced = True Then
'if there are no more dashes, and the game has been solved.
If lblSecretWord.Text.Contains("-") = False Then
MessageBox.Show("Great Job playing Hangman!", "Game Over", MessageBoxButtons.OK)
'Do this at start of game, player wants to see final score
'lblRemainingNumberOfAttempts.Text = ""
'lblNumberOfAttempts.Text = ""
Exit Sub
Else
blnDashReplaced = False
End If
End If
'This is a shorter way of incrementing a variable
intNumofGuesses += 1
'Can't put an integer into a Text property, it needs a string
lblNumberOfAttempts.Text = intNumofGuesses.ToString
'This is a shorter way of decrementing a variable
intNumberOfRemainingGuesses -= 1
'Can't put an integer into a Text property, it needs a string
lblRemainingNumberOfAttempts.Text = intNumberOfRemainingGuesses.ToString
Next
lblSecretWord.Text = "GAME OVER!"
MessageBox.Show("Better luck next time. Sorry the correct word was " & strSecretWord & ".", "You Lost", MessageBoxButtons.OK)
'Do this at start of game
'lblRemainingNumberOfAttempts.Text = ""
'lblNumberOfAttempts.Text = ""
End Sub
Private Sub btnSetUp_Click(sender As Object, e As EventArgs) Handles btnSetUp.Click
lblSecretWord.Text = ""
lblNumberOfAttempts.Text = "0"
lblRemainingNumberOfAttempts.Text = "0"
lbxLettersGuessed.Items.Clear()
'start game and have 1st user input a 5 letter word that 2nd player needs to guess
strSecretWord = InputBox("Please input a word for user to guess:", "Please input secret word.").ToUpper
End Sub
End Class

How to round time to the nearest quarter hour in word

I need to round time to the nearest quarter hour in a word document. I am not very good at coding.
After a fair bit of searching I have found some vba code but it doesn't quite work. The code is:
Sub Time()
Dim num() As String
Dim tod() As String
Dim temp As String
num = Split(Time, ":")
tod = Split(num(2), " ")
If Val(num(1)) < 15 Then
temp = "00"
ElseIf Val(num(1)) < 30 Then
temp = "15"
ElseIf Val(num(1)) < 45 Then
temp = "30"
ElseIf Val(num(1)) < 60 Then
temp = "45"
End If
gettime = num(0) + ":" + temp + ":00 " + tod(1)
End Function
End Sub
When I try to run it I get a message:
"Compile Error: Expected function or variable"
and "Time" on the fifth line of the code is highlighted which I think is where the program stops running.
The rest of the code in the form is as follows:
This module doesn't affect the time rounding issue but I am including it so as not to leave anything out.
Option Explicit
Sub ClusterCheck()
Dim i As Integer, k As Integer, iCluster As Integer, bResult As Boolean
Dim sFieldNameNo As String, sName As String
On Error Resume Next ' If the first formfield is a checkbox, this will bypass the error that Word returns
sName = Selection.FormFields(1).Name ' Get the name of the formfield
bResult = ActiveDocument.FormFields(sName).CheckBox.Value ' Get the result of the current formfield
sFieldNameNo = Number(sName) ' Get generic number
sName = Left(sName, Len(sName) - Len(sFieldNameNo)) ' Get generic name
' Determine how many fields are within the cluster group
iCluster = 1
Do Until ActiveDocument.Bookmarks.Exists(sName & iCluster) = False
iCluster = iCluster + 1
Loop
iCluster = iCluster - 1
' If the check field is true, turn all of the other check fields to false
Application.ScreenUpdating = False
If bResult = True Then
For k = 1 To iCluster
If k <> sFieldNameNo Then ActiveDocument.FormFields(sName & k).Result = False
Next
End If
Application.ScreenUpdating = True
End Sub
This is the Number module:
Option Explicit
Function Number(ByVal sNumber As String) As String
' This module finds the form fields number within the field name
' Loops through the field name until it only has the number
Do Until IsNumeric(sNumber) = True Or sNumber = ""
sNumber = Right(sNumber, Len(sNumber) - 1)
Loop
Number = sNumber
End Function
This is the protection module:
Option Explicit
Sub Protect()
ActiveDocument.Protect Password:="wup13", NoReset:=True, Type:=wdAllowOnlyFormFields
End Sub
Sub Unprotect()
ActiveDocument.Unprotect Password:="wup13"
End Sub
This is the code that activates on opening and closing the document:
Option Explicit
Sub Document_Open()
' Zooms to page width, turns on Hidden Text, and turns off ShowAll and Table Gridlines
With ActiveWindow.View
.Zoom.PageFit = wdPageFitBestFit
.ShowHiddenText = True
.TableGridlines = False
.ShowAll = False
End With
Options.UpdateFieldsAtPrint = False
End Sub
Sub Document_Close()
' Turn on ShowAll and Table Gridlines
With ActiveWindow.View
.ShowAll = True
.TableGridlines = True
End With
Options.UpdateFieldsAtPrint = True
End Sub
That's all the code in the form. I am not great at VBA but am hoping I can solve this issue (with a little help).
DETAILS OF EXTRA DUTY FORM
Persons details
Family name:
Given name(s):
Level:
No.:
Location:
Cost Centre Code:
Time worked
Were any days of the extra duty performed on a designated public/show holiday? Yes 0 No 0
If yes enter holiday date/details:
Time commenced: [Text Form Field]
Date:
Time ceased: [Text Form Field]
Date:
Total Overtime claimed:
Are you a shift worker? Yes 0 No 0
Details of extra duty performed:
Vehicle details
Car: Yes 0 No 0
Motorcycle: Yes 0 No 0
Registration no.:
Fleet no.:
Stationary vehicle hours:
Yes 0 No 0 (only use for stationary duties)
Vehicle odometer start:
Odometer finish:
Total kms:
Client’s details
Company/Organisation name:
Phone no.:
Contact name:
Job no.:
Payment for special services
Was payment received in advance? Yes 0 No 0
If Yes– Amount:
Receipt no.:
Date:
If No– Amount:
Invoice no.:
Date:
I, , certify the above information to be true
(Signature) (Date)
Manager certification (Checked with roster and certified correct)
(Signature) (Date)
The code from vbforums gives me a subscript out of range error when used as recommended.
In the VBA IDE you can get explanations of what keywords do by placing the cursor on a keyword and pressing F1. This will bring up the MS help page for that particular keyword.
In the OP code the main procedure is 'Time'. This will cause problems for VBA because this is the same as the Time keyword so we would effectively be saying
time(time)
and VBA will stop with an error because the second use of time will be interpreted as the sub time and not the VBA time function so you will get the error message 'Argument not optional'.
The code below will provide what the OP has requested.
Option Explicit
Sub test_gettime()
Dim myTime As String
myTime = Now()
Debug.Print myTime
Debug.Print Format(myTime, "hh:mm:ss")
Debug.Print gettime(Format(myTime, "hh:mm:ss"))
' without the format statement we should also get the date
myTime = Now()
Debug.Print
Debug.Print myTime
Debug.Print gettime(myTime)
End Sub
Public Function gettime(this_time As String) As String
Dim myTimeArray() As String
Dim myQuarterHour As String
myTimeArray = Split(this_time, ":")
' Note that myTimeArray has not been converted to numbers
' Comparison of strings works by comparing the ascii values of each character
' in turn until the requested logic is satisfied
Select Case myTimeArray(1)
Case Is < "15"
myQuarterHour = "00"
Case Is < "30"
myQuarterHour = "15"
Case Is < "45"
myQuarterHour = "30"
Case Is < "60"
myQuarterHour = "45"
Case Else
Debug.Print "More than 60 minutes in the hour??"
End Select
gettime = myTimeArray(0) + ":" + myQuarterHour + ":00 "
End Function

VBA 2012 - Need to return an error when a user enters text instead of a numbers

I am taking a VBA class and am completely stuck on this problem. We CANNOT use the masked text box, which would solve this problem. Instead the professor actually wants me to learn the code, can you imagine?
All kidding aside, the user needs to enter a gas price into a text box, then hit calculate to receive the total cost of the trip. There is much more to the interface but will spare you the details. If a user enters anything else number than a positive number with one decimal place, it should return an error. I have figured out 0 or 0000 as well as a negative number such as -3.45. Now I have to get any text or special characters to give me an error as well as something like 34.56.12.45. You never know, a user may feel the need to type in their IP address. The key to the assignment is that I catch all probable user errors.
Here is what I've written for the calculation as well as catch the errors. I have tried the Try/Catch statements as well. Nothing worked but I got the first two parts of the IF statement to work yet always failing on the last IF part until it gets to the calculation.
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
Dim Mileage As Decimal
Dim Miles As Decimal
Dim GasPrice As Decimal
Dim Cost As Decimal
If CDec(txtbxGasPrice.Text) = 0 Then
MessageBox.Show("Please enter a positive dollar amount")
txtbxGasPrice.Text = String.Empty
End If
If CDec(txtbxGasPrice.Text) < 0 Then
MessageBox.Show("Please enter a positive dollar amount")
txtbxGasPrice.Text = String.Empty
End If
If Cost = CDec((Miles / Mileage) * GasPrice) Then
Miles = CDec(lblTMiles.Text)
Mileage = CDec(lblMileage.Text)
GasPrice = CDec(txtbxGasPrice.Text)
lblTotalCost.Text = Cost.ToString("C2")
End If
If CBool(txtbxGasPrice.Text = "") Then
MsgBox("You must enter a dollar amount")
End If
*If Not IsNumeric(txtbxGasPrice.Text) Then
MessageBox.Show("Please enter a positive dollar amount")
txtbxGasPrice.Text = String.Empty*
End If
End Sub
'I have placed this at the top, in the middle, at the bottom but no luck. What am I missing?
Appreciate your thoughts - Lauren
This one seems to meet your criteria and pass David's tests:
Function IsValid(txt As String) As Boolean
If Not IsNumeric(txt) Then
Exit Function
End If
If Len(txt) < 2 Then
Exit Function
End If
If Not Mid(txt, Len(txt) - 1, 1) = "." Then
Exit Function
End If
If Not txt > 0 Then
Exit Function
End If
IsValid = True
End Function
This seems like a perfect application of regular expressions, but could be out of scope for this problem, maybe even better though vb has a Decimal.TryParse(or parse) that will take a string and try to parse it to a decimal.
http://msdn.microsoft.com/en-us/library/system.decimal.tryparse.aspx
on a side not I'm not 100% sure how it acts with xx.xx.xx but I'm betting it will fail and help your problem
I'm going to expand on CSgoose's idea to use RegEx, it seems a lot more reliable. I am very, very green when it comes to using RegEx but I try to work on Q's here at SO, so this may not be the optimal pattern to match, but a function like this seems to do the trick when I test a few value.
0/0.0/0.00 = False
-1.5 = False
1.5 = True
5.45 = False
Steve = False
Steve.6 = False
Steve6.58 = False
6.574.2 = False
A value that evaluates to 0 will return false. Negative values return false. Value must have a decimal component, be comprised of any # of digits (this can be tweaked if you want to limit it, eg., to ##.# format, etc.). Matches full text only, so things like IP addresses won't return true, etc.
NOTE This is VBA, but should be easily adaptable for your purposes)
Sub YourSub()
If Not IsMatch(CStr(txtbxGasPrice.Text)) Then
MsgBox "Please ensure that the value you enter is a positive dollar amount, to 1 decimal place!", vbCritical, "Invalid Gas Price Value!"
End IF
End Sub
This function requires enabling reference to Microsoft VBScript Regular Expressions 5.5, or you could use late-binding.
Function IsMatch(str As String) As Boolean
'Tests for a positive numeric value, formatted 0.0 with a mandatory decimal component
' exact match only
Dim re As RegExp
Dim allMatches As MatchCollection
Dim retVal As Boolean
retVal = False 'by default
If Not IsNumeric(str) Then GoTo EarlyExit 'ignore any non-numeric value
Set re = New RegExp
re.Pattern = "\d*\.[0-9]"
Set allMatches = re.Execute(str)
If allMatches.Count = 1 Then
'If there are multiple matches, then I think safe to say it's not a match,
' make sure it's a full string match
If str > 0 Then
retVal = (allMatches(0) = str)
End If
End If
EarlyExit:
Set re = Nothing
IsMatch = retVal
End Function
Update to force, for example, ##.# format, you could do
re.Pattern = "[1-9]?\d\.\d"

Unexpected String Results

I have the following code to check values entered into two input boxes, if both values are zero then the MsgBox should display "Stop!" (I will change this later to exiting the sub but I am using a MsgBox for testing)
From testing I've seen these results:
A zero in both strings produces the expected message box.
A non zero in the first string followed by any non zero value in the second string does nothing (as expected).
A zero in the first string followed by a second string value equal to or greater than 10 produces the message box (unexpected).
I've also noticed that if the second string is 6-9 it is displayed as x.00000000000001%. I think this is a floating point issue and could be related? This behaviour occurs without the IF... InStr function too.
Option Explicit
Sub Models()
Dim MinPer As String, MaxPer As String, Frmula As String
Dim Data As Worksheet, Results As Worksheet
Set Data = Sheets("Data")
Set Results = Sheets("Results")
Application.ScreenUpdating = False
MinPer = 1 - InputBox("Enter Minimum Threshold Percentage, do not include the % symbol", _
"Minimum?") / 100
MaxPer = 1 + InputBox("Enter Maximum Threshold Percentage, do not include the % symbol", _
"Maximum?") / 100
If (InStr(MinPer, "0") = 0) And (InStr(MaxPer, "0") = 0) Then
MsgBox "STOP!"
End If
' Remainder of code...
This is the most interesting problem I've come across so far in VBA and welcome any discussion about it.
Edit: I use this code to display on screen the paramaters for the end-user to see. Hence how I noticed the .00000000001% issue:
.Range("D2").Value = "Min is " & 100 - MinPer * 100 & "%"
.Range("D3").Value = "Max is " & MaxPer * 100 - 100 & "%"
Two things
1) Declare MinPer, MaxPer as Long or a Double and not a String as you are storing outputs from a calculation
2) Don't directly use the InputBox in the calculations. Store them in a variable and then if the input is valid then use them in the calculation
Dim MinPer As Double, MaxPer As Double, Frmula As String
Dim Data As Worksheet, Results As Worksheet
Dim n1 As Long, n2 As Long
Set Data = Sheets("Data")
Set Results = Sheets("Results")
Application.ScreenUpdating = False
On Error Resume Next
n1 = Application.InputBox(Prompt:="Enter Minimum Threshold Percentage, do not include the % symbol", _
Title:="Minimum?", Type:=1)
On Error GoTo 0
If n1 = False Then
MsgBox "User cancelled"
Exit Sub
End If
On Error Resume Next
n2 = Application.InputBox(Prompt:="Enter Maximum Threshold Percentage, do not include the % symbol", _
Title:="Maximum?", Type:=1)
On Error GoTo 0
If n2 = False Then
MsgBox "User cancelled"
Exit Sub
End If
If n1 = 0 And n2 = 0 Then
MsgBox "STOP!"
End If
MinPer = 1 - (Val(n1) / 100)
MaxPer = 1 + (Val(n2) / 100)
This is because the number "10" has a "0" in the string (second character) so both evaluate to true.
Try this instead:
If (MinPer = "0") And (MaxPer = "0") Then
MsgBox "STOP!"
End If
For additional control save the user input (MinPer , MaxPer) and THEN text them for validity before performing nay mathematical operations on them.
InStr(MinPer, "0") is just checking to see whether the string contains a zero
character.
You need to convert the string value to an integer. Use the IsNumeric and CInt functions
to do that. See this URL:
vba convert string to int if string is a number
Dim minPerINT as Integer
Dim maxPerINT as Integer
If IsNumeric(minPer) Then
minPerINT = CInt(minPer)
Else
minPerINT = 0
End If
If IsNumeric(maxPer) Then
maxPerINT = CInt(maxPer)
Else
maxPerINT = 0
End If
If minPerINT = 0 and maxPerINT=0 Then
MsgBox "STOP!"
End If
Depending on what data can be entered It may also be a good idea to check if the length
of the data is zero using the len() function.