How to use string in calculator script
How to use string in calculator script
Hello, on the old forum Laszlo posted an amazing script for making calculations anywhere. As I am noob 2.0 I cannot figure out how the convertions work. 8*3 I can work out, but after trying several combinations I don't know what to do when I want to convert 5 inches to cm. Nor the other way around.
What I've tried:
inch*5 (equals 0)
xinch*5 (equals 0)
5inch (equals 5)
5xinch (equals 5)
5*xinch (equals 0)
:=5*xinch (equals 0)
From cm to inches I don't even know where to start...
Kind regard,
jazz
Script:
https://www.autohotkey.com/board/topic/15675-monster-evaluate-math-expressions-in-strings/
What I've tried:
inch*5 (equals 0)
xinch*5 (equals 0)
5inch (equals 5)
5xinch (equals 5)
5*xinch (equals 0)
:=5*xinch (equals 0)
From cm to inches I don't even know where to start...
Kind regard,
jazz
Script:
https://www.autohotkey.com/board/topic/15675-monster-evaluate-math-expressions-in-strings/
Re: How to use string in calculator script
Code: Select all
MsgBox, % Eval(xinch " * 5")
It seems like he should have had it parse the variable names he set up from the string also, but apparently he didn't, so you have to use the variables concatenated to your string. Which make it really not that useful for this purpose because this does the same thing with a lot less overhead:
Code: Select all
xinch := 2.54
MsgBox, % xinch * 5
Re: How to use string in calculator script
Hey boiler, even if I copy and paste that concatenation (learnt a new word here), the result is 0. I agree, if typing that string is what you have to do to get the answer, it is too much of a hassle. Especially for AHK use. Pity, but the simple mathmatics (+ - / *) do work and are very handy.
Re: How to use string in calculator script
I searched some more and came across this script. It converts inches to cm and vice versa (change cm <--> inches and 2.54 to 0.393700787) by opening a message box. not bad actually...
Code: Select all
::i2c:: ; or ::c2i::
fileappend, %A_UserName% - %A_DD%%A_MM%%A_YYYY% - sqfcalc`n, p:/autohotkey/texts/log.txt
InputBox, UserInput, Inch, please enter inch., , 100, 280
UserInput *= 2.54
if ErrorLevel
MsgBox, CANCEL was pressed.
else
sleep 500
UserInput := Round(UserInput, 1)
StringReplace, UserInput, UserInput, ., `,
send {bs 1} %UserInput% cm
return
- flyingDman
- Posts: 2817
- Joined: 29 Sep 2013, 19:01
Re: How to use string in calculator script
Monster is a monster but...!
If you move this part: Note the global ! (or define locals first then the constants)
inside the eval() function
you can do this:
If you move this part:
Code: Select all
global
xe := 2.718281828459045, xpi := 3.141592653589793 ; referenced as "e", "pi"
xinch := 2.54, xfoot := 30.48, xmile := 1.609344 ; [cm], [cm], [Km]
xounce := 0.02841, xpint := 0.5682, xgallon := 4.54609 ; liters
xoz := 28.35, xlb := 453.59237 ; gramms
inside the eval() function
you can do this:
Code: Select all
MsgBox % Eval("inch*5") ;12.7
MsgBox % Eval("pi*1") ;3.14159
MsgBox % Eval("ounce*1") ;0.02841
14.3 & 1.3.7
Re: How to use string in calculator script
I'm doing something wrong, because the answer is still 0. What I do is, I literally type MsgBox, % Eval(xinch " * 5") somewhere and after that I use the hotkey to get the answer.
I also don't know what I do with the global lines either.
Thank you for your time and reactions! I better stick to copy and paste scripts, I'm afraid.
I also don't know what I do with the global lines either.
Thank you for your time and reactions! I better stick to copy and paste scripts, I'm afraid.
- flyingDman
- Posts: 2817
- Joined: 29 Sep 2013, 19:01
Re: How to use string in calculator script
I assume that you have saved the Monster Script in a Lib. It makes sense to put it there. You have not explained exactly what your intended use is. Eval() is used to take a string and convert it to an expression and evaluate or "resolve" it, rather than use (variables in) expressions to resolve mathematical operations (which typically only requires built-in functions and no external functions; see: https://www.autohotkey.com/docs/commands/Math.htm). If your intent is only to convert inches to cm or cm to inches (or similar conversions), this might not be the tool for you. The following might demonstrate it:
Compared to a simple "conversion" tool:
Code: Select all
gui, font, s14
gui, add, text, x10 w50 , string:
gui, add, edit, x+5 w300 gcalc vMyEdit ,
gui, add, text, x10 y+5 w50 , result:
gui, add, edit, x+5 w300 vMyRes ,
gui, show
return
calc:
gui, submit, nohide
guicontrol,, MyRes, % eval(MyEdit)
return
;-----------------monster ----------------------
Eval(x) { ; non-recursive PRE/POST PROCESSING: I/O forms, numbers, ops, ";"
Local FORM, FormF, FormI, i, W, y, y1, y2, y3, y4
xe := 2.718281828459045, xpi := 3.141592653589793 ; referenced as "e", "pi"
xinch := 2.54, xfoot := 30.48, xmile := 1.609344 ; [cm], [cm], [Km]
xounce := 0.02841, xpint := 0.5682, xgallon := 4.54609 ; liters
xoz := 28.35, xlb := 453.59237 ; gramms
FormI := A_FormatInteger, FormF := A_FormatFloat
SetFormat Integer, D ; decimal intermediate results!
RegExMatch(x, "\$(b|h|x|)(\d*[eEgG]?)", y)
FORM := y1, W := y2 ; HeX, Bin, .{digits} output format
SetFormat FLOAT, 0.16e ; Full intermediate float precision
StringReplace x, x, %y% ; remove $..
Loop
If RegExMatch(x, "i)(.*)(0x[a-f\d]*)(.*)", y)
x := y1 . y2+0 . y3 ; convert hex numbers to decimal
Else Break
Loop
If RegExMatch(x, "(.*)'([01]*)(.*)", y)
x := y1 . FromBin(y2) . y3 ; convert binary numbers to decimal: sign = first bit
Else Break
x := RegExReplace(x,"(^|[^.\d])(\d+)(e|E)","$1$2.$3") ; add missing '.' before E (1e3 -> 1.e3)
; literal scientific numbers between ‘ and ’ chars
x := RegExReplace(x,"(\d*\.\d*|\d)([eE][+-]?\d+)","‘$1$2’")
StringReplace x, x,`%, \, All ; % -> \ (= MOD)
StringReplace x, x, **,@, All ; ** -> @ for easier process
StringReplace x, x, +, ±, All ; ± is addition
x := RegExReplace(x,"(‘[^’]*)±","$1+") ; ...not inside literal numbers
StringReplace x, x, -, ¬, All ; ¬ is subtraction
x := RegExReplace(x,"(‘[^’]*)¬","$1-") ; ...not inside literal numbers
Loop Parse, x, `;
y := Eval1(A_LoopField) ; work on pre-processed sub expressions
; return result of last sub-expression (numeric)
If FORM = b ; convert output to binary
y := W ? ToBinW(Round(y),W) : ToBin(Round(y))
Else If (FORM="h" or FORM="x") {
SetFormat Integer, Hex ; convert output to hex
y := Round(y) + 0
}
Else {
W := W="" ? "0.6g" : "0." . W ; Set output form, Default = 6 decimal places
SetFormat FLOAT, %W%
y += 0.0
}
SetFormat Integer, %FormI% ; restore original formats
SetFormat FLOAT, %FormF%
Return y
}
Eval1(x) { ; recursive PREPROCESSING of :=, vars, (..) [decimal, no ";"]
Local i, y, y1, y2, y3
; save function definition: f(x) := expr
If RegExMatch(x, "(\S*?)\((.*?)\)\s*:=\s*(.*)", y) {
f%y1%__X := y2, f%y1%__F := y3
Return
}
; execute leftmost ":=" operator of a := b := ...
If RegExMatch(x, "(\S*?)\s*:=\s*(.*)", y) {
y := "x" . y1 ; user vars internally start with x to avoid name conflicts
Return %y% := Eval1(y2)
}
; here: no variable to the left of last ":="
x := RegExReplace(x,"([\)’.\w]\s+|[\)’])([a-z_A-Z]+)","$1«$2»") ; op -> «op»
x := RegExReplace(x,"\s+") ; remove spaces, tabs, newlines
x := RegExReplace(x,"([a-z_A-Z]\w*)\(","'$1'(") ; func( -> 'func'( to avoid atan|tan conflicts
x := RegExReplace(x,"([a-z_A-Z]\w*)([^\w'»’]|$)","%x$1%$2") ; VAR -> %xVAR%
x := RegExReplace(x,"(‘[^’]*)%x[eE]%","$1e") ; in numbers %xe% -> e
x := RegExReplace(x,"‘|’") ; no more need for number markers
Transform x, Deref, %x% ; dereference all right-hand-side %var%-s
Loop { ; find last innermost (..)
If RegExMatch(x, "(.*)\(([^\(\)]*)\)(.*)", y)
x := y1 . Eval@(y2) . y3 ; replace (x) with value of x
Else Break
}
Return Eval@(x)
}
Eval@(x) { ; EVALUATE PRE-PROCESSED EXPRESSIONS [decimal, NO space, vars, (..), ";", ":="]
Local i, y, y1, y2, y3, y4
If x is number ; no more operators left
Return x
; execute rightmost ?,: operator
RegExMatch(x, "(.*)(\?|:)(.*)", y)
IfEqual y2,?, Return Eval@(y1) ? Eval@(y3) : ""
IfEqual y2,:, Return ((y := Eval@(y1)) = "" ? Eval@(y3) : y)
StringGetPos i, x, ||, R ; execute rightmost || operator
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) || Eval@(SubStr(x,3+i))
StringGetPos i, x, &&, R ; execute rightmost && operator
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) && Eval@(SubStr(x,3+i))
; execute rightmost =, <> operator
RegExMatch(x, "(.*)(?<![\<\>])(\<\>|=)(.*)", y)
IfEqual y2,=, Return Eval@(y1) = Eval@(y3)
IfEqual y2,<>, Return Eval@(y1) <> Eval@(y3)
; execute rightmost <,>,<=,>= operator
RegExMatch(x, "(.*)(?<![\<\>])(\<=?|\>=?)(?![\<\>])(.*)", y)
IfEqual y2,<, Return Eval@(y1) < Eval@(y3)
IfEqual y2,>, Return Eval@(y1) > Eval@(y3)
IfEqual y2,<=, Return Eval@(y1) <= Eval@(y3)
IfEqual y2,>=, Return Eval@(y1) >= Eval@(y3)
; execute rightmost user operator (low precedence)
RegExMatch(x, "i)(.*)«(.*?)»(.*)", y)
If IsFunc(y2)
Return %y2%(Eval@(y1),Eval@(y3)) ; predefined relational ops
StringGetPos i, x, |, R ; execute rightmost | operator
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) | Eval@(SubStr(x,2+i))
StringGetPos i, x, ^, R ; execute rightmost ^ operator
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ^ Eval@(SubStr(x,2+i))
StringGetPos i, x, &, R ; execute rightmost & operator
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) & Eval@(SubStr(x,2+i))
; execute rightmost <<, >> operator
RegExMatch(x, "(.*)(\<\<|\>\>)(.*)", y)
IfEqual y2,<<, Return Eval@(y1) << Eval@(y3)
IfEqual y2,>>, Return Eval@(y1) >> Eval@(y3)
; execute rightmost +- (not unary) operator
RegExMatch(x, "(.*[^!\~±¬\@\*/\\])(±|¬)(.*)", y) ; lower precedence ops already handled
IfEqual y2,±, Return Eval@(y1) + Eval@(y3)
IfEqual y2,¬, Return Eval@(y1) - Eval@(y3)
; execute rightmost */% operator
RegExMatch(x, "(.*)(\*|/|\\)(.*)", y)
IfEqual y2,*, Return Eval@(y1) * Eval@(y3)
IfEqual y2,/, Return Eval@(y1) / Eval@(y3)
IfEqual y2,\, Return Mod(Eval@(y1),Eval@(y3))
; execute rightmost power
StringGetPos i, x, @, R
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ** Eval@(SubStr(x,2+i))
; execute rightmost function, unary operator
If !RegExMatch(x,"(.*)(!|±|¬|~|'(.*)')(.*)", y)
Return x ; no more function (y1 <> "" only at multiple unaries: --+-)
IfEqual y2,!,Return Eval@(y1 . !y4) ; unary !
IfEqual y2,±,Return Eval@(y1 . y4) ; unary +
IfEqual y2,¬,Return Eval@(y1 . -y4) ; unary - (they behave like functions)
IfEqual y2,~,Return Eval@(y1 . ~y4) ; unary ~
If IsFunc(y3)
Return Eval@(y1 . %y3%(y4)) ; built-in and predefined functions(y4)
Return Eval@(y1 . Eval1(RegExReplace(f%y3%__F, f%y3%__X, y4))) ; LAST: user defined functions
}
ToBin(n) { ; Binary representation of n. 1st bit is SIGN: -8 -> 1000, -1 -> 1, 0 -> 0, 8 -> 01000
Return n=0||n=-1 ? -n : ToBin(n>>1) . n&1
}
ToBinW(n,W=8) { ; LS W-bits of Binary representation of n
Loop %W% ; Recursive (slower): Return W=1 ? n&1 : ToBinW(n>>1,W-1) . n&1
b := n&1 . b, n >>= 1
Return b
}
FromBin(bits) { ; Number converted from the binary "bits" string, 1st bit is SIGN
n = 0
Loop Parse, bits
n += n + A_LoopField
Return n - (SubStr(bits,1,1)<<StrLen(bits))
}
Sgn(x) {
Return (x>0)-(x<0)
}
MIN(a,b) {
Return a<b ? a : b
}
MAX(a,b) {
Return a<b ? b : a
}
GCD(a,b) { ; Euclidean GCD
Return b=0 ? Abs(a) : GCD(b, mod(a,b))
}
Choose(n,k) { ; Binomial coefficient
p := 1, i := 0, k := k < n-k ? k : n-k
Loop %k% ; Recursive (slower): Return k = 0 ? 1 : Choose(n-1,k-1)*n//k
p *= (n-i)/(k-i), i+=1 ; FOR INTEGERS: p *= n-i, p //= ++i
Return Round(p)
}
Fib(n) { ; n-th Fibonacci number (n < 0 OK, iterative to avoid globals)
a := 0, b := 1
Loop % abs(n)-1
c := b, b += a, a := c
Return n=0 ? 0 : n>0 || n&1 ? b : -b
}
fac(n) { ; n!
Return n<2 ? 1 : n*fac(n-1)
}
Code: Select all
inch := 2.54
gui, font, s14
gui, add, edit, w300 vMyEdit,
gui, add, edit, w300 vMyRes,
gui, add, button,gItoC,Inch to CM
gui, add, button,x+5 gCtoI,CM to Inch
gui, show
return
ItoC:
gui, submit, nohide
guicontrol,, MyRes, % MyEdit * inch
return
CtoI:
gui, submit, nohide
guicontrol,, MyRes, % MyEdit / inch
return
14.3 & 1.3.7