混合运算的代码
(2019-06-19 17:00:21)
标签:
混合运算三角函数对数逻辑运算 |
分类: VB编程 |
混合运算的代码
假如文本框有这样一个算式:3 * 7 - ((2 + 18)/5 + 6),如何编写代码?
看起来是个很简单的式子,写起代码来却大费周章,耗费了我整整一天的时间。编程的思路最后归纳为:
1.整个算式当作字符串来处理,只是在具体计算时化为数值,结果再转为字符串
2.不断地用计算结果替换原单项计算式,例如用“21”替换“3 * 7”
解题步骤如下:
预备工作:
1.去掉字符串中的空格,上式就变成了这样的字符串:“3*7-((2+18)/5+6)”
2.将小写字母转换为大写字母
开始计算:
1.利用函数 FindPlace 查找括号的位置,取出括号及其中的算式作为一个子字符串。如上式中的“(2+18)”。
2.将去掉括号的算式(如果没有括号就将整个算式)交给 analyze 函数,按照乘、除、加减的顺序进行计算。
3.在进行单项计算时,先确定运算符的位置,以这个位置为基础,分别获取前后两个数据和运算符本身,如上式中的“2”、“18”、“+”。这个步骤中最麻烦的是对“-”号的处理,因为它既可表示减法,也可以表示负数。
4.根据运算符计算(这是最轻松的步骤了)
5.每进行完一次计算,都要将结果转换成字符串,去替换由数据和运算符组成的子字符串。如“20/5+6”,除完后,用商去替换“20/5”这个子字符串,得到一个新的字符串:“4+6”
6.重复步骤1-5,上式就依次变成:“3*7-10”、“21-10”、“11”,最后结果在Text2显示。
笔者根据以上叙述编写了代码。
本代码可以对2/8/16进制的数据进行运算(但计算结果均为10进制),这三种进制的输入规则是:在数据前加一个标识字母(大小写均可),字母B表示2进制,字母O表示8进制,字母H表示16进制,除了这三个字母和16进制数字
A-F,计算式中不能出现其它字母。
本代码还可以进行三角函数、对数、逻辑、角弧互换等运算
下面就动手实验:
新建一个窗体,添加两个文本框和一个按纽,其中Text1用于输入计算式,Text2用于显示计算结果。点击按纽就开始计算。
代码如下:
Option Explicit
Private Sub Text1_GotFocus()
Text1.SelStart = 0: Text1.SelLength = Len(Text1)
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then Command1_Click
End Sub
Private Sub Command1_Click()
Dim st As String
st = Text1
st = Replace(st, vbCrLf, "")
st = UCase(StrConv(Replace(st, " ", ""), 8)) '去掉空格全角转半角再转为大写
st = Replace(st, "LOG", "S0S") '对数改名
st = Replace(st, "SIN", "S1S") '正弦改名
st = Replace(st, "COS", "S2S") '余弦改名
st = Replace(st, "TAN", "S3S") '正切改名
st = Replace(st, "CTG", "S4S") '余切改名
st = Replace(st, "ANG", "S5S") '角度改名
st = Replace(st, "RAD", "S6S") '弧度改名
st = Replace(st, "NOT", "L7L") '非改名
st = Replace(st, "AND", "L8L") '与改名
st = Replace(st, "OR", "L9L")
st = Replace(st, "XOR", "LAL") '异或改名
st = Replace(st, "EQV", "LBL") '相符改名
st = Replace(st, "IMP", "LCL") '隐含改名
st = CheckString2(st): If InStr(st, "错误") Then MsgBox st: Exit
Sub
st = CheckData(st, "H"): If InStr(st, "错误") Then MsgBox st: Exit
Sub '如果数据有错误退出
st = CheckData(st, "O"): If InStr(st, "错误") Then MsgBox st: Exit
Sub
st = CheckData(st, "B"): If InStr(st, "错误") Then MsgBox st: Exit
Sub
Text2 = Operation(st)
End Sub
Private Function Operation(ByVal Dat1 As String) As String
Dim MyData1 As String, MyData2 As String, i As Integer, k As
Integer
Do While InStr(Dat1, "(") >
0
Loop
k = InStr(Dat1, ",") '逗号位置
If k Then
Else
End If
End Function
Private Function analyze2(ByVal Dat2 As String) As String
Dim i As Integer, z As String, nSt As String
nSt = Dat2
Do
Loop While InStr(2, nSt, "^") Or InStr(2, nSt, "*") Or InStr(2,
nSt, "/") Or InStr(2, nSt, "+") Or InStr(2, nSt, "-")
analyze2 = nSt
End Function
Private Function AngRadCount(ByVal Dat3 As String, Flags As
String) As String '角弧对数三角函数
On Error GoTo 100
Dim z As String, num As Double, n As Double, i1 As Integer, i2 As
Integer
Const p1 = 0.017453292
Const p2 = 3.1415926
z = Dat3
i1 = InStr(z,
Flags)
i2 = GetRearStr(z, Flags,
1)
If Len(z) = 0 Then Exit Function
If i1 = 2 Then i1 = 1: i2 = i2 + 1
'如果标识起始位置=2,那么前字符为无效,可将它替换掉
num = Val(z)
Select Case Flags
End Select
num = Round(num, 8)
AngRadCount = Replace(Dat3, Mid$(Dat3, i1, i2), Format(num))
'用计算后的字串替换原单项算式
100
End Function
Private Function operate2(ByVal Dat3 As String, sign As String)
As String '逻辑运算和五则运算
Dim L As Integer, k1 As Integer, k2 As Integer, S1 As String, S2 As
String, num As Double
S1 = Dat3: S2 = Dat3: L = IIf(InStr("+-*/^", sign), 2, 1)
k1 = GetFrontStr(S1, sign,
L)
k2 = GetRearStr(S2, sign, L) + Len(S1) 'S2:运算符后的数据,K2:运算式长度
If Len(S1) = 0 Or Len(S2) = 0 Then Exit Function
Select Case sign
End Select
num = Round(num, 8)
operate2 = Replace(Dat3, Mid$(Dat3, k1, k2), Format(num))
'用计算后的字串替换原单项算式
End Function
Private Function GetFrontStr(mSt As String, Flags As String, L
As Integer) As Integer '获取标识前的数据字串及起始位置
On Error GoTo 100
Dim i As Integer, k As Integer, z As String, n As String
i = InStr(L, mSt, Flags) '查找标识位置
z = Left$(mSt, i -
1)
For k = Len(z) To 1 Step -1
Next
k = k + 1
mSt = Mid$(z, k) '获得标识前的数据
GetFrontStr = k
100
End Function
Private Function GetRearStr(mSt As String, Flags As String, L As
Integer) As Integer '获取标识后的数据字串及长度
Dim i As Integer, k As Integer, n As String
k = InStr(L, mSt, Flags) + Len(Flags) '查找标识后数据起始位置
For i = k To
Len(mSt)
Next
mSt = Mid$(mSt, k, i -
k)
GetRearStr = Len(mSt) + Len(Flags) '获得标识+后数据长度
End Function
Private Function CheckData(ByVal mSt As String, Flags As String)
As String '判断数据是否合法
Dim i As Integer, j As Integer, k As Integer, L As Integer, z As
String, z1 As String
j = InStr(mSt,
Flags)
Do While j > 0
Loop
CheckData = IIf(Len(z1), z1, mSt)
End Function
'1.输入数据;2.输入数据进制;3.输出数据进制;4.结果保留的小数位
Private Function 进制转换(num As String, No1 As Integer, No2 As
Integer, Optional retain As Integer = 8) As String
On Error GoTo ERR1
Dim a As Double, b As Double, Dat1 As Double, Dat2 As Double
Dim t1 As String, t2 As String, t3 As String, E As String
Dim i As Integer, k As Integer, L As Integer, j As Boolean
Dim bj1 As Boolean '小数标记
Dim bj2 As Boolean '负数标记
'检查输入数据
t1 = UCase(Replace(num, ",", ""))
If Left(t1, 1) = "-" Then t1 = Mid(t1, 2): bj2 = True '如果是负数
t2 = "."
For i = 48 To 57: t2 = t2 & Chr(i): Next
For i = 65 To 90: t2 = t2 & Chr(i): Next
't2=".0123456789ABCDEF"
t2 = Left(t2, No1 + 1): L = Len(t1)
For i = 1 To L
Next
t2 = "": k = InStr(t1, ".")
Select Case k
End Select
If j Then Exit Function '如果数字位超过
If No1 = 10
Then
Else
End If
If No2 = 10
Then
Else
End If
ERR1:
Exit Function
100 '整数部分转换为10进制
L = Len(t1)
For i = 0 To L - 1
Next
Return
200 '小数部分转换为10进制
L = Len(t2): b = 0
For i = 1 To L
Next
Return
300 '整数部分转换为其它进制
k = 0: t1 = ""
Do
Loop While Dat1 > 0
Return
400 '小数部分转换为其它进制
k = 0: t2 = IIf(t1 = "", "0.", ".")
Do
Loop Until Dat2 = 0 Or k = retain '保留小数位
Return
500 '检查整数部分的位数
L = Len(t1)
Select Case No1
End Select
Return
600 '检查小数部分的位数
j = Len(t2) > 8
Return
End Function
Private Function CheckString2(ByVal mSt As String) As String
'判断计算式是否合法
Dim i As Integer
For i = 1 To Len(mSt)
Next i
If UBound(Split(mSt, "(")) <> UBound(Split(mSt, ")")) Then
mSt = "错误!表达式中括号不成对"
endcheck:
CheckString2 = mSt
End Function
OK,现在随便输入几个算式看看:
输入“b1010-((o2+18)/h5-h6)-o3*o7”,计算得:-9
输入“1010-hff*((o7-18)/ha-h6)/3*o7”,计算得:5234.5
输入“(hf*10*ha-b1010*50)/o31”,计算得:40
输入“SIN90",计算得:1
完全正确!
补充:
还有一种更为简单的办法(当然功能不如本代码多),代码如下:
Private Sub Command1_Click()
Dim OBJ As Object
Set OBJ = CreateObject("MSScriptControl.ScriptControl")'在工程中引用
Microsoft Script Control 1.0
OBJ.Language = "vbscript"
Text2 = OBJ.eval_r(Text1)
Set OBJ = Nothing
End Sub
注意3点:
1.计算式中不能有二进制数据,以字母“B”打头也不行;
2.16进制和8进制标记前要加上英文字符“&”。例如:&ha-&h6+&010
3.如果计算结果≥H80000000,则以负数表示,HFFFFFFFF表示为-1