Page 1 of 1

Is there a way to check if an expression returns numeric?

Posted: Tue Aug 20, 2013 5:13 pm
by PBExplorer12
Hi,

Is it possible to take a string, like "5 * 23", and 1) find out if it represents a numeric expression, and 2) Perform the calculation, if it's not already a single value?

I have an IsNumeric function from the web, but it doesn't work for arithmetic expressions.

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 6:12 pm
by Danilo
Try this:

Code: Select all

XIncludeFile "Evaluate.pbi" ; http://danilo.purearea.net/EvaluateExpression.zip

Debug Evaluate("5 * 23")

Debug Evaluate("some text")
It returns "ERROR" if it is not a valid expression.

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 6:30 pm
by STARGÅTE
With database:

Code: Select all


Enumeration
	#Database
EndEnumeration

Procedure.f Evaluate(String.s, X.f=0)
	Protected Result.s
	If DatabaseQuery(#Database, ReplaceString("SELECT ("+String+")", "x", StrF(X)))
		If NextDatabaseRow(#Database)
			Result = GetDatabaseString(#Database, 0)
		EndIf
		FinishDatabaseQuery(#Database)
		ProcedureReturn ValF(Result)
	Else
		ProcedureReturn NaN()
	EndIf
EndProcedure  

UseSQLiteDatabase()
OpenDatabase(#Database, ":memory:", "", "", #PB_Database_SQLite)

Debug Evaluate("1 + 2 * 3")
Debug Evaluate("x+18/(x*x)", 3)
Debug Evaluate("374*4+7*(83+99)-3*128")
Debug Evaluate("some text")

CloseDatabase(#Database)

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 7:07 pm
by PBExplorer12
Danilo wrote:Try this:

Code: Select all

XIncludeFile "Evaluate.pbi" ; http://danilo.purearea.net/EvaluateExpression.zip

Debug Evaluate("5 * 23")

Debug Evaluate("some text")
It returns "ERROR" if it is not a valid expression.
Cool, thanks.

It also returns "0" if it's a string without spaces. So if you try

sTestString = Evaluate( "what" )

, sTestString will contain "0".

If

sTestString = Evaluate( "What the...?" )

, then it returns "ERROR"

, as you mentioned.




I can work with that, easily. Thanks, Danilo.

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 7:10 pm
by PBExplorer12
STARGÅTE wrote:With database:

Code: Select all


Enumeration
	#Database
EndEnumeration

Procedure.f Evaluate(String.s, X.f=0)
	Protected Result.s
	If DatabaseQuery(#Database, ReplaceString("SELECT ("+String+")", "x", StrF(X)))
		If NextDatabaseRow(#Database)
			Result = GetDatabaseString(#Database, 0)
		EndIf
		FinishDatabaseQuery(#Database)
		ProcedureReturn ValF(Result)
	Else
		ProcedureReturn NaN()
	EndIf
EndProcedure  

UseSQLiteDatabase()
OpenDatabase(#Database, ":memory:", "", "", #PB_Database_SQLite)

Debug Evaluate("1 + 2 * 3")
Debug Evaluate("x+18/(x*x)", 3)
Debug Evaluate("374*4+7*(83+99)-3*128")
Debug Evaluate("some text")

CloseDatabase(#Database)

Huh. Didn't even think of getting a db result, that way. Might come in handy, thanks.

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 7:13 pm
by Danilo
PBExplorer12 wrote:
Danilo wrote:Cool, thanks.

It also returns "0" if it's a string without spaces. So if you try

sTestString = Evaluate( "what" )

, sTestString will contain "0".

If

sTestString = Evaluate( "What the...?" )

, then it returns "ERROR"

, as you mentioned.




I can work with that, easily. Thanks, Danilo.
Please re-download EvaluateExpression.zip

Added #evalError_VariableNotDefined error, so Evaluate("what") returns "ERROR". You can change this behavior in the following procedure:

Code: Select all

Procedure.s __getEvaluateVariable(name.s)
    If FindMapElement(EvaluateVariables(),name)
        ProcedureReturn Trim(EvaluateVariables())
    EndIf
    ;ProcedureReturn "0"     ; unknown variables = 0
    ProcedureReturn "ERROR"  ; unknown variables = ERROR -> #evalError_VariableNotDefined
EndProcedure

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 7:22 pm
by akj
Here's a function I've successfully used for quite a while:

Code: Select all

Procedure.i IsNumeric(num$) ; AKJ  07-Mar-11
; Tests whether the given value is purely numeric
; If an exponent is present, it will never be classed as a integer
; A number like 5.00 will be classed as an integer
; Return:  -1 if a floating-point number  1 if an integer  0 otherwise
Protected dp, ep, exp$="", signs, status
Select CountString(num$, ".") ; Number of decimal points
  Case 0: status = 1 ; Potentially an integer
  Case 1: status = -1 ; Potentially a float
  Default: ProcedureReturn 0 ; Not a number
EndSelect
; See if an exponent is present
ep = FindString(UCase(num$), "E", 1)
If ep ; If an exponent
  status = -1 ; Actually a float
  exp$ = Mid(num$, ep+1) ; Exponent
  num$ = Left(num$, ep-1) ; Mantissa
  ; Count and remove leading exponent +/- signs
  signs = 0
  While Left(exp$,1)="+" Or Left(exp$,1)="-"
    signs + 1: exp$ = Mid(exp$, 2)
  Wend
  If signs>1: ProcedureReturn 0: EndIf ; Text
  exp$ = LTrim(exp$, "0") ; Remove leading exponent zeros
  If Str(Val(exp$))<>exp$: ProcedureReturn 0: EndIf ; Text
EndIf
; Count and remove leading mantissa +/- signs
signs = 0
While Left(num$,1)="+" Or Left(num$,1)="-"
  signs + 1: num$ = Mid(num$, 2)
Wend
If signs>1: ProcedureReturn 0: EndIf ; Text
dp = FindString(num$, ".", 1) ; Location of any decimal point
If dp
  If exp$+RemoveString(Mid(num$, dp+1), "0")="": status = 1: EndIf ; Integer if fractional part is zero
  num$ = RemoveString(num$, ".") ; Remove decimal point
EndIf
If num$="": ProcedureReturn 0: EndIf ; Null string
num$ = Trim(num$, "0") ; ; Remove outer mantissa zeros
; Ensure the mantissa is purely numeric
If num$ And (Str(Val(num$))<>num$): status = 0: EndIf ; Use quad precision ???
ProcedureReturn status
EndProcedure

; Examples:
Debug IsNumeric("00") ; 1
Debug IsNumeric("0.0") ; 1
Debug IsNumeric("X") ; 0
Debug IsNumeric("E") ; 0
Debug IsNumeric(".") ; 0
Debug IsNumeric("") ; 0
Debug IsNumeric("0") ; 1
Debug IsNumeric("1"); 1
Debug IsNumeric(".0"); 1
Debug IsNumeric(".1") ; -1
Debug IsNumeric("0.1"); -1
Debug IsNumeric("1.0") ; 1
Debug IsNumeric("1.1") ; -1
Debug IsNumeric("0.") ; 1
Debug IsNumeric("1.") ; 1
Debug IsNumeric("-5.1E-7") ; -1
Debug IsNumeric("-5.0E-7") ; -1
Debug IsNumeric("-5E-7") ; -1
Debug IsNumeric("-E-7") ; 0
Debug IsNumeric("56789") ; 1
Debug IsNumeric("-56.789") ; -1

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 7:44 pm
by PBExplorer12
Danilo wrote:
PBExplorer12 wrote:
Danilo wrote:Cool, thanks.

It also returns "0" if it's a string without spaces. So if you try

sTestString = Evaluate( "what" )

, sTestString will contain "0".

If

sTestString = Evaluate( "What the...?" )

, then it returns "ERROR"

, as you mentioned.




I can work with that, easily. Thanks, Danilo.
Please re-download EvaluateExpression.zip

Added #evalError_VariableNotDefined error, so Evaluate("what") returns "ERROR". You can change this behavior in the following procedure:

Code: Select all

Procedure.s __getEvaluateVariable(name.s)
    If FindMapElement(EvaluateVariables(),name)
        ProcedureReturn Trim(EvaluateVariables())
    EndIf
    ;ProcedureReturn "0"     ; unknown variables = 0
    ProcedureReturn "ERROR"  ; unknown variables = ERROR -> #evalError_VariableNotDefined
EndProcedure

Works great, thanks.

Re: Is there a way to check if an expression returns numeric

Posted: Tue Aug 20, 2013 7:45 pm
by PBExplorer12
akj wrote:Here's a function I've successfully used for quite a while:

Code: Select all

Procedure.i IsNumeric(num$) ; AKJ  07-Mar-11
; Tests whether the given value is purely numeric
; If an exponent is present, it will never be classed as a integer
; A number like 5.00 will be classed as an integer
; Return:  -1 if a floating-point number  1 if an integer  0 otherwise
Protected dp, ep, exp$="", signs, status
Select CountString(num$, ".") ; Number of decimal points
  Case 0: status = 1 ; Potentially an integer
  Case 1: status = -1 ; Potentially a float
  Default: ProcedureReturn 0 ; Not a number
EndSelect
; See if an exponent is present
ep = FindString(UCase(num$), "E", 1)
If ep ; If an exponent
  status = -1 ; Actually a float
  exp$ = Mid(num$, ep+1) ; Exponent
  num$ = Left(num$, ep-1) ; Mantissa
  ; Count and remove leading exponent +/- signs
  signs = 0
  While Left(exp$,1)="+" Or Left(exp$,1)="-"
    signs + 1: exp$ = Mid(exp$, 2)
  Wend
  If signs>1: ProcedureReturn 0: EndIf ; Text
  exp$ = LTrim(exp$, "0") ; Remove leading exponent zeros
  If Str(Val(exp$))<>exp$: ProcedureReturn 0: EndIf ; Text
EndIf
; Count and remove leading mantissa +/- signs
signs = 0
While Left(num$,1)="+" Or Left(num$,1)="-"
  signs + 1: num$ = Mid(num$, 2)
Wend
If signs>1: ProcedureReturn 0: EndIf ; Text
dp = FindString(num$, ".", 1) ; Location of any decimal point
If dp
  If exp$+RemoveString(Mid(num$, dp+1), "0")="": status = 1: EndIf ; Integer if fractional part is zero
  num$ = RemoveString(num$, ".") ; Remove decimal point
EndIf
If num$="": ProcedureReturn 0: EndIf ; Null string
num$ = Trim(num$, "0") ; ; Remove outer mantissa zeros
; Ensure the mantissa is purely numeric
If num$ And (Str(Val(num$))<>num$): status = 0: EndIf ; Use quad precision ???
ProcedureReturn status
EndProcedure

; Examples:
Debug IsNumeric("00") ; 1
Debug IsNumeric("0.0") ; 1
Debug IsNumeric("X") ; 0
Debug IsNumeric("E") ; 0
Debug IsNumeric(".") ; 0
Debug IsNumeric("") ; 0
Debug IsNumeric("0") ; 1
Debug IsNumeric("1"); 1
Debug IsNumeric(".0"); 1
Debug IsNumeric(".1") ; -1
Debug IsNumeric("0.1"); -1
Debug IsNumeric("1.0") ; 1
Debug IsNumeric("1.1") ; -1
Debug IsNumeric("0.") ; 1
Debug IsNumeric("1.") ; 1
Debug IsNumeric("-5.1E-7") ; -1
Debug IsNumeric("-5.0E-7") ; -1
Debug IsNumeric("-5E-7") ; -1
Debug IsNumeric("-E-7") ; 0
Debug IsNumeric("56789") ; 1
Debug IsNumeric("-56.789") ; -1
Thanks, akj.