I'm creating a chatbot using VB6 and the whole basis of this chatbot is that whenever a user writes a 'trigger word', such as "good", "amazing", etc., the chatbot will reply "that's great".
However, whenever I don't write the trigger word, only the msgbox which says "Word is in this" appears, and I don't know what I'm doing wrong. I've tried messing around with the >, <, = signs to no avail. Any help will be appreciated.
Private Sub conversation()
Dim imput As String 'where user types to chatbot
Dim arrWords As Variant, aWord As Variant
arrWords = Array("good", "great", "bad")
Dim wordFound As Boolean
wordFound = False
For Each aWord In arrWords
If InStr(imput, aWord) = 0 Then
wordFound = True And MsgBox "Word is in this"
ElseIf InStr(imput, aWord) > 0 Then
wordFound = False And MsgBox "Word is not in this"
End If
Next
End Sub
Other answers have already explained that your logic is backwards, which it is.
But also, I don't know whether you have accurately copied your code or not, but when I copy it into VB, I get — as I expected — syntax errors on the lines with MsgBox in them. I can "fix" this by adding parentheses to the MsgBox arguments, so: wordFound = True And MsgBox("Word is in this"), etc. But that isn't good code, for reasons I will explain, and I have a few other suggestions.
Consider these changes to your code:
Private Sub conversation(theInput As String)
Dim arrWords As String, aWord As String
arrWords = Array("good", "great", "bad")
Dim wordFound As Boolean
wordFound = False
For Each aWord In arrWords
If InStr(theInput, aWord) = 0 Then
wordFound = False
MsgBox """" & aWord & """ is in this"
Else
wordFound = True
MsgBox """" & aWord & """ is not in this"
End If
Next
End Sub
Private Sub SendButton_Click()
conversation(myChatTextBox.Text)
End Sub
Ok. Here are some points.
Don't use Variant unless you have a compelling reason to do so. It's the least efficient way to store information, because it has to allocate extra memory to tell internally what type of variable it is, and it also has to allocate enough memory to contain the largest possible type it could be. (A String variable has 10 bytes plus one per character in the string, while a Variant type allocated as a string has 22 bytes plus one per character in the string.)
I changed imput to theInput. input is a reserved word in VB, so you can't use it, but it's clearer to other people if you don't misspell the word. Better to find some prefix to put on it.
As others have said, when InStr returns zero, that means that the string in argument 2 isn't in the string in argument 1. So, it means that the "word isn't in this," not that it is. (That's the answer to the trouble you're having; the rest of this is just to improve your code overall.)
wordFound = True And MsgBox("Word is in this") only works by coincidence. MsgBox returns a value of 1 when it runs successfully without arguments. (Who knew? I had to try it out for myself. Probably because it can be set up to return a number of different values for different types of ms) So your logic is wordFound = True And 1. And is a logical comparison operator: True And 1 evaluates to True, while False And 1 evaluates to False. So, you get what you want, but pretty much by accident. Put the two code bits on two different lines. You don't need to logically compare them; in fact it doesn't make sense to do so. (If you want to actually put two lines of code on the same line, put a colon between them: wordFound = True : MsgBox "etc", but this isn't generally considered good practice as the code is less readable. I have the feeling you thought you were using And to do this, and as you can see it does something quite different.)
I changed your message to include the word you're looking for in quotes, for example "good" is in this. To get a literal quotation mark in a string, use two of them: "". (You have to put the two quotes in quotes themselves, since they are a quoted string; that's why there are four of them at the beginning and three later on.)
You don't need an ElseIf here, because if your If condition is false, your ElseIf condition is true. You only need ElseIf if you are evaluating more than two possible conditions.
I've set up the basic idea of how to send the chatbox user's input to your conversation subroutine. When the user clicks a Send button, you send the contents of the text box to conversation as the input argument. If you set it up as a local variable, you have to write some sort of code to grab the user's input. This is the cleaner way to do the job.
All that said, you can further simplify your For Each loop like this:
For Each aWord In arrWords
wordFound = InStr(input, aWord) > 0
MsgBox """" & aWord & """ is" & IIf(wordFound, "", " not") & " in this"
Next
Explanations:
InStr(input, aWord) <> 0 is either true or false. You assign whichever it is to wordFound. This is a more concise way of doing your If...Else. (A simpler example of the idea: x = 1 = 1 will set x equal to True, while x = 1 = 0 will set x equal to false. You can use parentheses to make it easier to understand: x = (1 = 1), etc.)
IIf ("instant if") takes the form of IIf(condition, valueIfConditionIsTrue, valueIfConditionIsFalse).
Since wordFound is a boolean value, saying wordFound is the same as saying wordFound = True, so you can omit the = True (you can also say Not wordFound to mean the same thing as wordFound = False).
EDIT: If you want your chatbot to reply "that's great" when any one of the words is encountered, change conversation() from a Sub to a Function and return true or false. Like this:
Private Function conversation(theInput As String) As Boolean
Dim arrWords As String, aWord As String
arrWords = Array("good", "great", "bad")
'Get rid of your wordFound variable — you don't need it any more
conversation = False
For Each aWord In arrWords
If InStr(theInput, aWord) > 0 Then
conversation = True
End If
Next
End Function
Private Sub SendButton_Click()
If conversation(myChatTextBox.Text)
MsgBox "That's great!"
Else
MsgBox "That's not so great."
End If
End Sub
Jim Mack's answer is correct; I would make the comparison more robust by adding (before the for loop):
imput = UCase(imput)
and making the array of test words all uppercase. Fundamentally, there was just a logic problem with the original code (probably due to a misunderstanding of the language).
The ElseIf clause is somewhat worrisome, too; in general, it's wise to include an explicit else clause to handle any test that falls through all the previous conditions.
I didn't try to run your code -- it doesn't even look like it would run -- but at least one error jumps out.
If InStr(imput, aWord) = 0 Then
wordFound = True And MsgBox "Word is in this"'
...doesn't do what you seem to think it does. You're saying that wordFound will be true when the word is NOT in the input (InStr = 0), but only when the MsgBox returns a non-zero result
What you want is something like:
If InStr(imput, aWord) > 0 Then ' >0 means word was found
wordFound = True
MsgBox "Word is in this"'
The parallel is true for the 'not found' condition.
I have a string that contains digits inside. For example, "adf20j83n,m3jh2k9". Is there a direct way to count the number of digits inside the string. As in my example, it should give me "7" as an output.
Also, I have tried RegExp but it's not working in VBScript in QTP.
Btw, I'm not looking for loops and stuff like that. Just a direct way, or a suggestion to make this RegExp work in QTP.
You'll probably need to create the COM object via its ProgId:
Dim re
Set re = CreateObject("VBScript.RegExp")
re.Pattern = "\d"
re.Global = True
MsgBox "Digits: " & re.Execute("adf20j83n,m3jh2k9").Count
Output:
Digits: 7
I know it's techically what you said but it's a good way nonetheless
Try using this function:
Public Sub CountNumeric(ByVal input As String)
Dim numericCount As Integer = 0
For Each c As Char In input
If Char.IsDigit(c) Then numericCount += 1
Next
MessageBox.Show(String.Format("Number of numerics : {0}", numericCount)
End Sub
EDIT:
You could also try this:
Dim charColl As MatchCollection = Regex.Matches(input , "^\d+$")
Console.WriteLine(charColl.Count.ToString())
I want to replace a particular value followed by TRN* to some other value.How to do the coding for the same?..Please provide an example.
For example :
TRN*12345*34444~
This is a segment in my file(like this I have many TRN* segments in my file).I want to replace the segment after TRN* and before next * (ie.12345)with some other value.
Is there any way to do this by using vbscript?
Thanks in advance
The regular expression way of safetyOtter is the way to go, you only have to fiddle with the pattern and replacement string:
originalString = "TRN*12345*34444~"
replaceValue = "78910"
Set re = new RegExp
re.Pattern = "(.*TRN\*)([^*]+)(.*)"
re.IgnoreCase = False
' This keeps the first and last part between parenthesis, but replaces the middle part
newString = re.Replace(originalString, "$1" & replaceValue & "$3")
msgbox newString
' result: TRN*78910*34444~
Something like this should work, may have to tweak, can't test it at the moment
Set regEx = New RegExp
regEx.Pattern = "TRN\*.*?\*"
regEx.IgnoreCase = True
replStr = "TRN*" & SomeOtherValue& "*"
ReplaceTest = regEx.Replace(YourStringHere, replStr)
Edit:
if you are looking to replace a specific number with another, a simple:
YourStringHere = Replace(YourStringHere,"TRN*12345*","TRN*67890*")
Is enough
I know I can split a string into multiple substrings by giving a delimiter. I know I can also choose a substring based on character position like this:
sAddressOverflow = Right(sAddressLine1,5)
What I would like to do though is split an input string like this:
"123 South Main Street Apt. 24B"
But I only want to end up with two substrings which are split based on the first space to the left of the 25th character. So my desired output using the above input would be:
Substring1 = "123 South Main Street"
Substring2 = "Apt. 24B"
Is this possible?
Regular expressions have the advantage that you can configure your pattern independently from the location where you use it and that they are highly adaptable, so I prefer to do string manipulation with regular expressions. Unfortunately the pattern of Ansgar Wiechers does not exactly match your requirement. Here is one that does:
myString = "1234 6789A 234567 9B12 4567 890"
Set re = new RegExp
re.Pattern = "^(.{1,25}) (.*)$"
Set matches = re.Execute(myString)
wscript.echo "leftpart: " & matches(0).submatches(0)
wscript.echo "rightpart: " & matches(0).submatches(1)
There is no such inbuilt function available,
but you might want to try this,
add = "123 South Main Street Apt. 24B"
valid = Left(add,25)
arr = Split(valid)
char= InStrRev(add,arr(UBound(arr)))-1
address1 = Left(add,char)
address2= Right(add,Len(add)-char)
Wscript.echo address1
Wscript.echo address2
this might not be the perfect way, but it works !!!
You can do this with a regular expression, but you need a well defined format:
addr = "123 South Main Street Apt. 24B"
Set re = New RegExp
re.Pattern = "^(\d+ .*) +(apt\. +\d+(.*?))$"
re.IgnoreCase = True
Set m = re.Execute(addr)
If m.Count > 0 Then
WScript.Echo m(0).SubMatches(0)
WScript.Echo m(0).SubMatches(1)
End If
By "well-defined format" I mean that you need some "anchors" (or fix points) in your expression to identify the parts in the string. In the example the anchor is the substring "apt." followed by one or more digits.
Is there something like this, that only leaves numbers, letters and underscore for spaces?
Server.URLEncode isn't quite what i'm looking for.
There is no an integrated function as you described in ASP.
But you can do with regular expressions.
May be as follows:
Function FileNameEncode(ByVal strFileName)
Dim oReg
Set oReg = New RegExp
oReg.IgnoreCase = True
oReg.Global = True
oReg.Pattern = "[^a-z\d\s.]+"
FileNameEncode = Replace(oreg.Replace(strFileName, ""), " ", "_")
Set oReg = Nothing
End Function
'FileNameEncode("letters é$- 123ÖÇ.bat") returns "letters__123.bat"
If you pass filename without extension as parameter, you could remove the dot char from pattern.