-
Jul 3rd, 2014, 09:33 AM
#1
Thread Starter
Fanatic Member
[RESOLVED (or sort of...)]Evaluating boolean value of a string...?
Hi all.
I need to evaluate boolean values of strings, and I'd like to avoid coding the entire thing. So I'm wondering if some of you might point me toward a solution.
For example, I may have a strings with the following content:
"PB1=PB2" (which should return FALSE)
"LS1 like LS*" (which should return TRUE)
"LT11 <> LT2" (which should return TRUE)
Is there something that could interpret that already, and just return the result?
Thanks for your help!
Cheers,
Last edited by Alain; Jul 3rd, 2014 at 06:17 PM.
Don't ask why, just reboot!
-
Jul 3rd, 2014, 10:14 AM
#2
Re: Evaluating boolean value of a string...?
You could try using a script control and evaluate the string with it
-
Jul 3rd, 2014, 10:51 AM
#3
Thread Starter
Fanatic Member
Re: Evaluating boolean value of a string...?
Thanks. I didn't know about the Scriptcontrol. It seems to be a possible solution, if I can only learn how to use wildcards in the eval function. (ex: "LS1 = LS*" should return TRUE. Haven't been able to make it work, wether I used * or %, or even with 'Like' instead of '='...).
Don't ask why, just reboot!
-
Jul 3rd, 2014, 11:17 AM
#4
Re: Evaluating boolean value of a string...?
-
Jul 3rd, 2014, 11:21 AM
#5
Re: Evaluating boolean value of a string...?
well LS1 = LS* (and also LS1 like LS*) doesn't make sense... uynless both are strings... in which case it should be "LS1" like "LS*" .... but then again... that doesn't make sense because it will only equate out when LS1 = LS1. So... I guess the question is what is LS1, PB1, etc?
-tg
-
Jul 3rd, 2014, 11:47 AM
#6
Thread Starter
Fanatic Member
Re: Evaluating boolean value of a string...?
Yes, LS1, LS2, PB1, etc. are all string values.
Originally Posted by techgnome
in which case it should be "LS1" like "LS*" .... but then again... that doesn't make sense because it will only equate out when LS1 = LS1.
I think it makes sense. "LS(whatever)" should return TRUE when compared to "LS*" with the "Like" comparator. "LS1" was just an example that should return TRUE as well. I get a 'sub or function not define' error with the eval function whenever using the "like" comparator. Bummer.
Don't ask why, just reboot!
-
Jul 3rd, 2014, 01:47 PM
#7
Re: Evaluating boolean value of a string...?
What you need to explain is where does string come from?
The string has the name LS1 or a string that contains "LS1"?
And why is LS1 = LS2 false?
What is the rule we need to follow (why false/true)
-
Jul 3rd, 2014, 02:10 PM
#8
Thread Starter
Fanatic Member
Re: Evaluating boolean value of a string...?
I appreciate the help guys, but I have a hard time being more clear about the situation. Where the strings come from is irrelevant. The point is I have string values that will be structured as boolean expressions, and I want to evaluate those expression to know if they are true or false. The EVAL function of the ScriptingControl would completely solve my problem, if it wasn't on for the fact that using wildcards doesn't seem to work with it.
Here is another example, in case it helps:
Let's say I have the following string value: "456 > 347". If I evaluate this boolean expression, it should return TRUE (which the EVAL function of the scripting control does).
Let's say I have the following other string value: "ALW457 Like ALW*". It should also return TRUE, and that is where the ScriptingControl fails to help me...
Last edited by Alain; Jul 3rd, 2014 at 04:20 PM.
Don't ask why, just reboot!
-
Jul 3rd, 2014, 04:50 PM
#9
Re: Evaluating boolean value of a string...?
You should be indicating to the Scriptcontrol that the values are strings. I don't know how it expects that to be done, perhaps like this:
Code:
" 'ALW457' Like 'ALW*' "
or perhaps like this:
Code:
" ""ALW457"" Like ""ALW*"" "
Alternatively you could split the entire string into 3 parts (value1, operator, value2), and write a Select Case to evaluate it, eg:
Code:
Dim result as Boolean
Select Case operator
Case "="
result = (value1 = value2)
Case "Like"
result = (value1 Like value2)
....
Case Else
MsgBox "Invalid operator specified"
End Select
-
Jul 3rd, 2014, 06:16 PM
#10
Thread Starter
Fanatic Member
Re: Evaluating boolean value of a string...?
Originally Posted by si_the_geek
You should be indicating to the Scriptcontrol that the values are strings. I don't know how it expects that to be done, perhaps like this:
Code:
" 'ALW457' Like 'ALW*' "
or perhaps like this:
Code:
" ""ALW457"" Like ""ALW*"" "
That's what I did and and doesn't work (just for the 'Like' comparator. All others work.)
Originally Posted by si_the_geek
Alternatively you could split the entire string into 3 parts (value1, operator, value2), and write a Select Case to evaluate it, eg:
Code:
Dim result as Boolean
Select Case operator
Case "="
result = (value1 = value2)
Case "Like"
result = (value1 Like value2)
....
Case Else
MsgBox "Invalid operator specified"
End Select
That's what I wanted to avoid, but I guess I don't have much choice. I'll probably use the ScriptControl for all other tests, and use my code (or should I say 'yours'..) when the 'Like' operator will be used.
Thanks all. ( I guess I can consider this one resolved, sort of...)
Don't ask why, just reboot!
-
Jul 3rd, 2014, 07:09 PM
#11
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
You do know that the ScriptControl can run VBScript, right? That's what it's for... that's why it's called "ScriptControl" and not "runSomeSimpleCodeControl" ... I've done some fairly complicated stuff with it... it CAN evaluate your tests PROVIDED you do it right.
It's been a few years and I no longer have the code, but I built a system that gave our clients the ability to creating pricing scenarios by using a simple menuing system and storing it in the database. Then at run-time, it was assembled into VBScript code, sent to the SC and executed.
As an example of what the code would look like:
Code:
function Hours
Hours = 85
end function
function Rate
Rate = 5
end function
function OverTimeRate
OverTimeRate = Rate * 1.5
end function
function CalcPay
if Hours > 40 then
CalcPay = 40 * Rate + ((Hours - 40) * OverTimeRate)
else
CalcPay = Rate * Hours
End function
The CalcPay function is then invoked (I don't remember how to do this, but you need to know the name of the function you're invoking, I do remember that part).
So you CAN accomplish what you want BUT, it has to be set up right... you can't just sent it "LS1 like LS*" ... that's meaningless. You have to think about it in terms of VBScript... is LS1 the literal string? or is it a variable? That's why we keep asking about that, but for what ever reason, you're being somewhat vague about it. Maybe it's a lack of understanding, which is fine, we've all had to deal with that at some level at some point.
Code:
Function CheckValue
CheckValue = "SL1" like "LS*"
End Function
-tg
-
Jul 3rd, 2014, 07:48 PM
#12
Thread Starter
Fanatic Member
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
Originally Posted by techgnome
You do know that the ScriptControl can run VBScript, right? That's what it's for... that's why it's called "ScriptControl" and not "runSomeSimpleCodeControl" ... I've done some fairly complicated stuff with it... it CAN evaluate your tests PROVIDED you do it right.
(...)
So you CAN accomplish what you want BUT, it has to be set up right... you can't just sent it "LS1 like LS*" ... that's meaningless. You have to think about it in terms of VBScript... is LS1 the literal string? or is it a variable? That's why we keep asking about that, but for what ever reason, you're being somewhat vague about it. Maybe it's a lack of understanding, which is fine, we've all had to deal with that at some level at some point.
techgnome, please remain respectful.
First off, I never said I wanted to use VBScript using ScriptControl. I said I wanted to evaluate boolean expressions. It was suggested to me to use the ScriptControl (including by you, by the way).
Secondly, I believe I was not vague about the nature of the values I want to evaluate. I have mentioned quite clearly in my last post I was talking about string values. Never mentioned string variables.
Originally Posted by Alain
The point is I have string values that will be structured as boolean expressions
Originally Posted by Alain
Let's say I have the following string value: "456 > 347".
Originally Posted by Alain
Let's say I have the following other string value: "ALW457 Like ALW*"
But thanks anyway.
Don't ask why, just reboot!
-
Jul 4th, 2014, 12:22 PM
#13
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
I think your 'major' problem using the script control is that vbScript doesn't support the 'Like' operator. Also you need to embed the string varialbe names in double quotes:
Code:
Mydata(1) = """LK*"" Like ""LK123"""
as has already been mentioned.
It looks as if the script control wont help you mach so you're going to have to manually parse each record and process accordingly.
You could play with something like this
Code:
Option Explicit
Private Sub Form_Load()
Dim MyData(5) As String
Dim sFirst As String, sSecond As String, sOperator As String
Dim bResult As Boolean
Dim i As Integer, iPos1 As Integer, iPos2 As Integer, iPos3 As Integer
MyData(0) = "435 > 123"
MyData(1) = "LK* Like LK123"
MyData(2) = "123 = 234"
MyData(3) = "1 = 1"
MyData(4) = "12 <> 13"
MyData(5) = "34 <> 34"
For i = 0 To UBound(MyData)
iPos1 = InStr(MyData(i), " ")
If iPos1 > 0 Then
sFirst = Trim$(Mid$(MyData(i), 1, iPos1 - 1))
iPos2 = InStr(iPos1 + 1, MyData(i), " ")
If iPos2 > 0 Then
sOperator = Trim$(Mid$(MyData(i), iPos1 + 1, iPos2 - (iPos1 + 1)))
iPos3 = InStr(iPos2 + 1, MyData(i), " ")
If iPos3 > 0 Then
sSecond = Trim$(Mid$(MyData(i), iPos3 + 1))
Else
sSecond = Trim$(Mid$(MyData(i), iPos2 + 1))
End If
Else
MsgBox ("Malformed Expression - Space character missing between Operator and Second variable")
End If
Else
MsgBox ("Malformed Expression - Space character missing between First variable and Operator")
End If
Select Case sOperator
Case ">"
If sFirst > sSecond Then
bResult = True
Else
bResult = False
End If
Case "<"
If sFirst < sSecond Then
bResult = True
Else
bResult = False
End If
Case "="
If sFirst = sSecond Then
bResult = True
Else
bResult = False
End If
Case "<>"
If sFirst <> sSecond Then
bResult = True
Else
bResult = False
End If
Case "Like"
If sSecond Like sFirst Then
bResult = True
Else
bResult = False
End If
Case Else
MsgBox ("Unsupported Operator" & sOperator)
End Select
MsgBox (sFirst & " " & sOperator & " " & sSecond & " is " & bResult)
Next i
End Sub
-
Jul 4th, 2014, 12:55 PM
#14
Thread Starter
Fanatic Member
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
Whoohoo! Free code!
Thanks Doogle!
Don't ask why, just reboot!
-
Jul 4th, 2014, 03:47 PM
#15
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
As Doogle already demonstrated - it is possible to leave String-Literals "un-escaped"
(without enclosing the Str-Content in quotes), when the Script-Interpreter or -Parser
remains simple and forgoes support for Function-symbols, and Variable- + Const-symbols,
containing (aside from the operators) only either numeric-values or non-numeric values,
the latter then being treated as String-Literals (without quoting).
A fully implemented interpreter-language of course has support for Functions and Vars,
so String-Literal-escaping cannot be avoided (to be able to spearate them from the symbols).
http://en.wikipedia.org/wiki/Literal...programming%29
Below is a very simple expression parser, which demonstrates unescaped mode (by leaving out
function-support) - and so we can write in the DirectWindow for example expressions like this:
? Eval("foobar Like foo* AND foobar Like *bar AND (1 + 2) * 4 - 1 = 11")
True
? Eval("D_1x5 Like [A-F]_?x?")
True
? Eval("((1 + -2) * -3 + 4) * 2 / 7 * 216 ^ (-1 / -3)")
12
The parser supports the Operators as listed in the code below - as well as a VB-like
Operator-precedence, and parentheses to define ones own precedences are allowed too.
Best put into a Module, to be able to do testing in the DirectWindow without starting the IDE
Code:
Option Explicit
Public Function Eval(ByVal Expr As String)
Dim L As String, R As String
Do While HandleParentheses(Expr): Loop
If 0 Then
ElseIf Spl(Expr, "Or", L, R) Then: Eval = Eval(L) Or Eval(R)
ElseIf Spl(Expr, "And", L, R) Then: Eval = Eval(L) And Eval(R)
ElseIf Spl(Expr, ">=", L, R) Then: Eval = Eval(L) >= Eval(R)
ElseIf Spl(Expr, "<=", L, R) Then: Eval = Eval(L) <= Eval(R)
ElseIf Spl(Expr, "=", L, R) Then: Eval = Eval(L) = Eval(R)
ElseIf Spl(Expr, ">", L, R) Then: Eval = Eval(L) > Eval(R)
ElseIf Spl(Expr, "<", L, R) Then: Eval = Eval(L) < Eval(R)
ElseIf Spl(Expr, "Like", L, R) Then: Eval = Eval(L) Like Eval(R)
ElseIf Spl(Expr, "&", L, R) Then: Eval = Eval(L) & Eval(R)
ElseIf Spl(Expr, "-", L, R) Then: Eval = Eval(L) - Eval(R)
ElseIf Spl(Expr, "+", L, R) Then: Eval = Eval(L) + Eval(R)
ElseIf Spl(Expr, "Mod", L, R) Then: Eval = Eval(L) Mod Eval(R)
ElseIf Spl(Expr, "\", L, R) Then: Eval = Eval(L) \ Eval(R)
ElseIf Spl(Expr, "*", L, R) Then: Eval = Eval(L) * Eval(R)
ElseIf Spl(Expr, "/", L, R) Then: Eval = Eval(L) / Eval(R)
ElseIf Spl(Expr, "^", L, R) Then: Eval = Eval(L) ^ Eval(R)
ElseIf Len(Expr) Then: Eval = IIf(Val(Expr), Val(Expr), Trim(Expr))
End If
End Function
Private Function HandleParentheses(Expr As String) As Boolean
Dim P As Long, i As Long, C As Long
P = InStr(Expr, "(")
If P Then HandleParentheses = True Else Exit Function
For i = P To Len(Expr)
If Mid(Expr, i, 1) = "(" Then C = C + 1
If Mid(Expr, i, 1) = ")" Then C = C - 1
If C = 0 Then Exit For
Next i
Expr = Left(Expr, P - 1) & Str(Eval(Mid(Expr, P + 1, i - P - 1))) & Mid(Expr, i + 1)
End Function
Private Function Spl(Expr As String, Op$, L$, R$) As Boolean
Dim P As Long
If (InStr("*[?", Left(Trim(Expr), 1)) Or InStr("*]?", Right(Trim(Expr), 1))) _
And InStr("*-", Op) Then Exit Function Else P = InStrRev(Expr, Op, , 1)
If P Then Spl = True Else Exit Function
R = Mid(Expr, P + Len(Op))
L = Trim(Left$(Expr, IIf(P > 0, P - 1, 0)))
Spl = IIf(Len(L) = 0 Or InStr("+*/\^&<>", Right(L, 1)) And _
InStrRev(L, " ") = Len(L) - 1, 0, 1)
If Right(L, 1) = "-" Then R = "-" & R
End Function
Olaf
Last edited by Schmidt; Jul 4th, 2014 at 06:14 PM.
-
Jul 4th, 2014, 03:59 PM
#16
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
And to post an example of a simple expression-parser which has support for your own
Userdefined functions - demonstrating, that it is not possible anymore, to work with
un-escaped String-Literals. So all of those have to be enclosed in single Quotes now
(similar to SQL-StringLiterals), to allow for some easier typing in VB6.
Here's an already somewhat larger list of Test-Cases, which all evaluate to the same result as VB6:
Code:
Option Explicit
'just a group of Test-calls for the simple Evaluator (in comparison to VB-outputs)
'the VB6-resolved expression is always located directly below the Eval-String to
'be able to compare the test-expressions more easily ...
'(results are printed side-by-side and should come out the same in all test-cases)
Private Sub Form_Load()
'simple operator-precedence without parentheses
Debug.Print Eval("1 + 6 / 3 - 7"), _
1 + 6 / 3 - 7
'unary-operator test
Debug.Print Eval("-1 + -6 / 3 - -7 "), _
-1 + -6 / 3 - -7
'simple parentheses test
Debug.Print Eval("-14 / 7 * -(1 + 2)"), _
-14 / 7 * -(1 + 2)
'a complex case, including exponent-handling
Debug.Print Eval("((1 + -2) * -3 + 4) * 2 / 7 * 216 ^ (-1 / -3) "), _
((1 + -2) * -3 + 4) * 2 / 7 * 216 ^ (-1 / -3)
'operator-precedence (mainly to test Mod and Div operators)
Debug.Print Eval("27 / 3 Mod (5 \ 2) + 23"), _
27 / 3 Mod (5 \ 2) + 23
'function-calls
Debug.Print Eval("43 + -(-2 - 3) * Abs(Cos(4 * Atn(1)))"), _
43 + -(-2 - 3) * Abs(Cos(4 * Atn(1)))
'simple case, but mixed with a string-concat (math-ops have precedence)
Debug.Print Eval("5 + 3 & 2"), _
5 + 3 & 2
'simple case of a string-concat (notation for string-literals as in SQL)
Debug.Print Eval("'abc ' & '123 ' & 'xyz'"), _
"abc " & "123 " & "xyz"
'simple comparison-ops follow... (starting with a string-comparison)
Debug.Print Eval("'abc' > '123'"), _
"abc" > "123"
'comparison of numbers... math-ops have precedence
Debug.Print Eval("3 = 1 + 2"), _
3 = 1 + 2
'comparison of strings per Like-Operator...
Debug.Print Eval("'abc' Like '*b*'"), _
"abc" Like "*b*"
'comparison of strings per Like-Operator (using the "in-range" notation)
Debug.Print Eval("'3xB..foo' Like '[1-5]?[A-C]*o'"), _
"3xB..foo" Like "[1-5]?[A-C]*o"
'and here logical comparisons, involving the And-Operator (a mix of String- and Value-Compares)
Debug.Print Eval("'foobar' Like 'foo*' And 'foobar' Like '*bar' And (1 + 2) * 4 - 1 = 11"), _
"foobar" Like "foo*" And "foobar" Like "*bar" And (1 + 2) * 4 - 1 = 11
End Sub
And here the basically similar expression-parser-code to the one above (but with addded function-support).
Code:
Option Explicit
Public Function Eval(ByVal Expr As String)
Dim L As String, R As String
Do While HandleParentheses(Expr): Loop
If 0 Then
ElseIf Spl(Expr, "Or", L, R) Then: Eval = Eval(L) Or Eval(R)
ElseIf Spl(Expr, "And", L, R) Then: Eval = Eval(L) And Eval(R)
ElseIf Spl(Expr, ">=", L, R) Then: Eval = Eval(L) >= Eval(R)
ElseIf Spl(Expr, "<=", L, R) Then: Eval = Eval(L) <= Eval(R)
ElseIf Spl(Expr, "=", L, R) Then: Eval = Eval(L) = Eval(R)
ElseIf Spl(Expr, ">", L, R) Then: Eval = Eval(L) > Eval(R)
ElseIf Spl(Expr, "<", L, R) Then: Eval = Eval(L) < Eval(R)
ElseIf Spl(Expr, "Like", L, R) Then: Eval = Eval(L) Like Eval(R)
ElseIf Spl(Expr, "&", L, R) Then: Eval = Eval(L) & Eval(R)
ElseIf Spl(Expr, "-", L, R) Then: Eval = Eval(L) - Eval(R)
ElseIf Spl(Expr, "+", L, R) Then: Eval = Eval(L) + Eval(R)
ElseIf Spl(Expr, "Mod", L, R) Then: Eval = Eval(L) Mod Eval(R)
ElseIf Spl(Expr, "\", L, R) Then: Eval = Eval(L) \ Eval(R)
ElseIf Spl(Expr, "*", L, R) Then: Eval = Eval(L) * Eval(R)
ElseIf Spl(Expr, "/", L, R) Then: Eval = Eval(L) / Eval(R)
ElseIf Spl(Expr, "^", L, R) Then: Eval = Eval(L) ^ Eval(R)
ElseIf Trim(Expr) >= "A" Then: Eval = Fnc(Expr)
ElseIf Len(Expr) Then: Eval = IIf(InStr(Expr, "'"), _
Replace(Trim(Expr), "'", ""), Val(Expr))
End If
End Function
Private Function HandleParentheses(Expr As String) As Boolean
Dim P As Long, i As Long, C As Long
P = InStr(Expr, "(")
If P Then HandleParentheses = True Else Exit Function
For i = P To Len(Expr)
If Mid(Expr, i, 1) = "(" Then C = C + 1
If Mid(Expr, i, 1) = ")" Then C = C - 1
If C = 0 Then Exit For
Next i
Expr = Left(Expr, P - 1) & Str(Eval(Mid(Expr, P + 1, i - P - 1))) & Mid(Expr, i + 1)
End Function
Private Function Spl(Expr As String, Op$, L$, R$) As Boolean
Dim P As Long
P = InStrRev(Expr, Op, , 1)
If P Then Spl = True Else Exit Function
If P < InStrRev(Expr, "'") And InStr("*-", Op) Then P = InStrRev(Expr, "'", P) - 1
R = Mid(Expr, P + Len(Op))
L = Trim(Left$(Expr, IIf(P > 0, P - 1, 0)))
Select Case Right(L, 1)
Case "", "+", "*", "/", "A" To "z": Spl = False
Case "-": R = "-" & R
End Select
End Function
Private Function Fnc(Expr As String)
Expr = LCase(Trim(Expr))
Select Case Left(Expr, 3)
Case "abs": Fnc = Abs(Val(Mid$(Expr, 4)))
Case "sin": Fnc = Sin(Val(Mid$(Expr, 4)))
Case "cos": Fnc = Cos(Val(Mid$(Expr, 4)))
Case "atn": Fnc = Atn(Val(Mid$(Expr, 4)))
Case "log": Fnc = Log(Val(Mid$(Expr, 4)))
Case "exp": Fnc = Exp(Val(Mid$(Expr, 4)))
'etc...
End Select
End Function
Note, that both parsers are not meant for production-usage, because their test-coverage
is basically only the cases you see in Form-Load above - and although some expressions there
seems "quite complex and impressive" (to be solved by such a small thing) - there's better
and also faster parsers out there - the VBScript-Control being the first among them.
Olaf
Last edited by Schmidt; Jul 4th, 2014 at 06:16 PM.
-
Jul 4th, 2014, 04:35 PM
#17
Thread Starter
Fanatic Member
Re: [RESOLVED (or sort of...)]Evaluating boolean value of a string...?
Wow Olaf!
This is great. Thanks for taking the time to do this, and to explain it as well as you did. It is very appreciated!
Cheers,
Don't ask why, just reboot!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|