简介:
由于windows自带的计算器需要手动点点点实现加减乘除计算很是不方便,而且也记不住命令行打开的命令,最近就用ahk做了一个计算器,最开始想要自己做界面,后来发现自己做的界面很丑,而且不符合我最小依赖开发的理念。由于平时习惯用windows的运行框,然后就想能不能把计算结果整合到运行框中,后来发现运行的输入框是个控件,我们只需要获取输入,然后处理,然后把输出结果写入运行框中,完全不会影响运行框既有的功能。
最开始我想调用js来计算字符串表达式的值,但是计算**(幂)的时候不太方便,而且要u32版本才支持,后来纯用ahk代码逆波兰表达式也能实现计算字符串表达式的值。
使用步骤:
- 用win+R 打开运行框
- 输入计算表达式(代码自动识别 带有数字和运算符(+加,-减 ,*乘,/除,**幂,%模))
- 在表达式后面输入== ,输入框中就会计算出结果值。
- 由于输入框中只能输入 250个字符左右,当表达式字符超过35就只会显示结果,因为输入框可见长度就35左右,前面的字符就会隐藏。
运行效果:
扩展:
当然这个运行框不但可以计算一些数学表达式,还可以计算一些其它的东西,我这里只是抛砖引玉,各位同学可以发挥自己的想象,对下面代码稍加修改就可以实现很多计算功能。
我给大家列举我想到并已经完成的操作:
- 计算asc 码,输入 asc x 得到asc码,chr x 得到码值对应的字符
- 计算汉字unicode编码,unicode编码转为汉字
- 进制键转换 10进制,16进制,2进制互相转换
- 大小写转换 up xx =大写字符, down xx =小写字符
- 计算字符长度 len xx=n , lenx xx=n 计算16进制长度, 由于这个字符串很长可能运行框装不下我们可以先复制,然后获取粘贴板的值len[粘贴板]=n
- 正则表达式测试
- 获取计算机的关键信息, 例如 cpuid =xxx
- 计算平均值 ,avg 10 20 30= xxx
- 时间转换,1天=xx小时,xx分,xx秒 xx毫秒 或者 72小时=xx天,xx分,xx秒,xx毫秒 等
- 翻译,mean 中文=英文 或者 英文=中文 ,这个直接调用搜狗翻译,爬取结果即可,不用申请百度云等接口。
- 直接打开某个应用,输入baidu 打开百度,输入idea运行idea,输入目录打开目录,原理:创建一个配置文件,把所有的映射关系写到配置文件,例如:baidu=http://www.baidu.com 换行,idea=idea.exe,检测运行框回车事件,获取框中值,找到映射关系,然后用执行RUN xxx 就可以运行,当然如果啥都没匹配到那么我们就发送回车,执行系统的运行框的运行,这样不会影响系统本来的功能。
还可以用来实现啥,请各位同学踊跃补充,想看完整实现的也可以在下方评论,我把完整的代码贴出来,因为现有代码实在太长了,代码多了容易眼花缭乱。
上代码:
#If WinActive(Util.decodeUtf8("\u8FD0\u884C"))
;执行强大的计算功能
:*?:==::
;获取输入框文本
ControlGetText, inputCmd , Edit1, % Constant.RUN_BOX_TITLE
result:=RunBoxUtil.getResult(inputCmd)
;计算出错了,具体原因不详
if(result=="err")
{
height:=A_ScreenHeight-164
ToolTip ,% Constant.CALCULATE_ERR,235,142
SetTimer, RemoveToolTip, 3000
return
}
ControlsetText, % Constant.RUN_BOX_CONTROL,% result, % Constant.RUN_BOX_TITLE
ControlSend, % Constant.RUN_BOX_CONTROL, {END}, % Constant.RUN_BOX_TITLE
;记录日志
Util.writeToLog(Constant.AHK_CALCULATE_LOG, RunBoxUtil.EXPRESSION ,RunBoxUtil.OPERATE) ;写入日志
return
class RunBoxUtil
{
;excel计算对象
;static oExcel := ComObjCreate("Excel.Application")
;当前是什么操作
static OPERATE:=""
;当前表达式
static EXPRESSION:=""
;获取计算结果
getResult(rawStr)
{
;原始字符串写入日志
logRawStr:=rawStr
;去掉左边空格
rawStr:=trim(rawStr)
;计算数学表达式
tempStr:=RegExReplace(rawStr,"[a-zA-Z]+","")
if(tempStr==rawStr)
{
if(InStr(rawStr, "+")>0 || InStr(rawStr, "-")>0 || InStr(rawStr, "*")>0 || InStr(rawStr, "/")>0
||InStr(rawStr, "%")>0 || InStr(rawStr, "**")>0)
{
leftExpression:=RegExReplace(rawStr,"\s+","")
;result:=Util.calcuateExpressions(rawStr)
result:=Util.polish_notation(rawStr) ;无需调用js,用逆波兰表达式计算值
result:=RegExReplace(result,"\.0+$","") ;去掉 2.000这样式的
if(InStr(result,".")>0)
result:=RegExReplace(result,"0+$","") ;去掉2.1200这样的
fullExpression:= leftExpression "=" result
RunBoxUtil.OPERATE:=Util.decodeUtf8("\u6570\u5B66\u8868\u8FBE\u5F0F\u8BA1\u7B97")
RunBoxUtil.EXPRESSION:=logRawStr "=" result
if(strLen(fullExpression)>35)
return result
return fullExpression
}
}
return rawStr
}
}
;自定义工具类
Util
{
;逆波兰表达式https://blog.csdn.net/assiduous_me/article/details/101981332:
polish_notation(expression)
{
operatorlevel_map:={"(":0,"+":"1","-":1,"*":2,"/":"2","%":2,"^":3,")":4}
operator_list:={"+":0,"-":0,"*":0,"/":0,"%":0,"^":0}
;去除不必要的空格
expression:=trim(expression)
expression:=RegExReplace(expression,"\s+","")
;替换立方根
StringReplace expression,expression,**,^,all
;替换负数
StringReplace expression,expression,`(-,`(0-,all
;msgBox % expression
;①.获取一个中缀表达式集合类似 100+2 -> ["100","+","2"]
middlefix_list:=[]
fix:=""
loop ,parse,expression
{
current_value:=A_LoopField
if(operatorlevel_map.haskey(current_value))
{
if(""!=fix)
middlefix_list.push(fix)
middlefix_list.push(current_value)
fix:=""
}else fix:=fix current_value
}
if(fix!="")
middlefix_list.push(fix)
if(middlefix_list[1]="-") ;处理开头为负数
{
middlefix_list.insertAt(1,"(")
middlefix_list.insertAt(2,"0")
middlefix_list.insertAt(5,")")
}
;②.转换为后缀表达式(逆波兰表达式)
operator_stack:=[]
suffix_list:=[]
for index ,currentElmt in middlefix_list
{
if(operator_list.haskey(currentElmt))
{
while(operator_stack.length()>0 && operatorlevel_map[operator_stack[operator_stack.Length()]]>=operatorlevel_map[currentElmt])
suffix_list.push(operator_stack.pop())
operator_stack.push(currentElmt)
}else if(currentElmt="(")
operator_stack.push("(")
else if(currentElmt=")")
{
while(operator_stack.length()>0 && operatorlevel_map[operator_stack[operator_stack.length()]]>operatorlevel_map["("])
suffix_list.push(operator_stack.pop())
if(operator_stack.length()>0)
operator_stack.pop()
}
else
suffix_list.push(currentElmt)
}
while(operator_stack.length()>0)
suffix_list.push(operator_stack.pop())
;③.计算表达式最终的值,规则数字入栈,操作符就出栈两个元素计算值并把结果入栈
number_stack:=[]
for key,opertor_or_number in suffix_list
{
if(operator_list.haskey(opertor_or_number))
{
number2:=number_stack.pop()
number1:=number_stack.pop()
if(opertor_or_number="+")
number_stack.push(number1+number2)
if(opertor_or_number="-")
number_stack.push(number1-number2)
if(opertor_or_number="*")
number_stack.push(number1*number2)
if(opertor_or_number="/")
number_stack.push(number1/number2)
if(opertor_or_number="%")
number_stack.push(mod(number1,number2))
if(opertor_or_number="^")
number_stack.push(number1**number2)
}else
number_stack.push(opertor_or_number)
}
result:=number_stack.pop()
return result
}
;对utf-8解码
decodeUtf8(value)
{
i := 0
while (i := InStr(value, "\",, i+1)) {
if !(SubStr(value, i+1, 1) == "u")
this.ParseError("\", text, pos - StrLen(SubStr(value, i+1)))
uffff := Abs("0x" . SubStr(value, i+2, 4))
if (A_IsUnicode || uffff < 0x100)
value := SubStr(value, 1, i-1) . Chr(uffff) . SubStr(value, i+6)
}
Return,value
}
}
分享的内容很不错,排版可能还需要优化,感谢分享!
其实可以装一个Python当计算器用,可以满足你提到的大部分需求……
就是仿照的python的idle.
大佬,代码不全,能更新一下不
如果是数学计算的话是没啥问题了,其它功能的话代码太多了,等空了把那些补充上去。