这是上回Kivic(Kivic) 大哥教我的没有变量的程序,我现在还是不会改成有变量的。 模块代码: '计算用户输入的表达式 '如 "3+2*2" 结果为 "7"Public Function 计算(GS As String) As String Dim i, n As Integer Dim TempGs, Temp As String Dim Vl() As String '操作数 Dim Vls As Integer '操作数的数目 Dim Si As Integer '上一操作符的位置 Dim Ads, Sus, Mus, Bys, Lks, Rks As Integer '操作符的数目 Dim Adp(), Mup(), Byp(), Lkp(), Rkp() As Integer '操作符的位置 Dim Adn(), Mun(), Byn() As Integer '操作符的排列次序 Dim Sig() As Integer '每一个操作符的位置
On Error GoTo Err Do While True ReDim Adp(Len(GS)), Mup(Len(GS)), Byp(Len(GS)) _ , Lkp(Len(GS)), Rkp(Len(GS)) As Integer ReDim Adn(Len(GS)), Mun(Len(GS)), Byn(Len(GS)) _ , Lkn(Len(GS)), Rkn(Len(GS)), Sig(Len(GS)) As Integer
ReDim Vl(Len(GS))
If Len(GS) = 0 Then GoTo Err If Mid(GS, Len(GS), 1) <> "#" Then
TempGs = GS For i = 1 To Len(GS) '将减化加
If Mid(GS, i, 1) = "-" And i <> 1 Then If Mid(GS, i - 1, 1) <> "+" And Mid(GS, i - 1, 1) <> "-" _ And Mid(GS, i - 1, 1) <> "*" And Mid(GS, i - 1, 1) <> "/" Then TempGs = Mid(TempGs, 1, i - 1 + n) + "+" + Mid(GS, i) n = n + 1 End If
End If Next i GS = TempGs
n = 0 For i = 1 To Len(GS) '处理负负得正 If Mid(GS, i, 1) = "-" Then If Mid(GS, i + 1, 1) = "-" Then TempGs = Mid(TempGs, 1, i - 1 - n) + Mid(GS, i + 2) n = n + 2 End If End If Next i GS = TempGs GS = GS + "#" End If
Select Case Mid(GS, i, 1) Case "+" Ads = Ads + 1 Adp(Ads) = i Adn(Ads) = Vls Case "*" Mus = Mus + 1 Mup(Mus) = i Mun(Mus) = Vls Case "/" Bys = Bys + 1 Byp(Bys) = i Byn(Bys) = Vls Case "(" Lks = Lks + 1 Lkp(Lks) = i
Case ")" Rks = Rks + 1 Rkp(Rks) = i
End Select
If Mid(GS, i, 1) = "+" Or Mid(GS, i, 1) = "*" Or _ Mid(GS, i, 1) = "/" Or Mid(GS, i, 1) = "#" Then
If Si + 1 = i And Mid(GS, i + 1, 1) <> "#" _ Then '操作符非法连续或以操作符开头 GoTo Err Else Si = i End If
If Not IsNumeric(Vl(Vls)) And Mid(GS, i + 1, 1) <> "#" _ Then '操作数不是数字 GoTo Err End If Sig(Vls) = i Vls = Vls + 1
Else If Mid(GS, i, 1) <> "(" And Mid(GS, i, 1) <> ")" Then Vl(Vls) = Vl(Vls) + Mid(GS, i, 1) '制作操作数 Else If i <> 1 Then If ((Mid(GS, i - 1, 1) = "(" And Mid(GS, i, 1) = ")") Or _ (Mid(GS, i - 1, 1) = ")" And Mid(GS, i, 1) = "(")) _ Then '判定括号前后符号的合法性 GoTo Err End If End If End If End If
Next i
If Lks <> Rks Then GoTo Err '左右括号数是否匹配 End If
For i = 1 To Lks If Lkp(i) > Rkp(i) Then GoTo Err '左右括号出现顺序错误 Next i
If Lks <> 0 Then '括号处理 Do While True For i = Lks To 1 Step -1 For n = Rks To 1 Step -1 Temp = 计算(Mid(GS, Lkp(i) + 1, Rkp(n) - Lkp(i) - 1)) If Temp <> "公式有错误" Then GS = Mid(GS, 1, Lkp(i) - 1) + Temp + Mid(GS, Rkp(n) + 1) Exit Do End If Next n Next i If Temp = "公式有错误" Then GoTo Err '括号中有错误退出 Loop Else If Mus <> 0 Then '乘法处理 GS = Mid(GS, 1, Sig(Mun(1) - 1)) + Trim(Str(Val(Vl(Mun(1))) _ * Val(Vl(Mun(1) + 1)))) + Mid(GS, Val(Mup(1)) + Len(Vl(Mun(1) _ + 1)) + 1) Else If Bys <> 0 Then '除法处理 GS = Mid(GS, 1, Sig(Byn(1) - 1)) + Trim(Str(Val(Vl(Byn(1))) _ / Val(Vl(Byn(1) + 1)))) + Mid(GS, Val(Byp(1)) + Len(Vl(Byn(1) _ + 1)) + 1) Else If Ads <> 0 Then '加法处理 GS = Trim(Str(Val(Vl(1)) + Val(Vl(2)))) + Mid(GS, Val(Adp(1)) _ + Len(Vl(2)) + 1) Else 计算 = Mid(GS, 1, Len(GS) - 1) Exit Function End If End If End If End If Loop
hehe...看看这个吧,把编译作业重做了一遍^_^Option Explicit '(C)LengDakun '表达式计算 '1、变量识别 '2、表达式构建 '3、计算 ' '建立变量标识对照,建立逆波兰表达式。 ' 表达式由数字,变量,运算符组成 '定义:运算符:+,-,*,/,(,) ' 运算优先级别:(, ), */, +- Type ExpType a As Integer 'Attribute of a word v As Double 'Value of a word End TypeConst EXP_NONE = 0 'None Const EXP_VAL = 1 'Value 'Const EXP_VAR = 2 'Variable Const EXP_OPR = 3 'OperatorPrivate Contrast(1 To 128) As String, ConMax As Integer Private Value(1 To 128) As Double Private vs As String, vo As StringSub Main() Dim OrgExp As String Dim E(255) As ExpType, Emax As Integer Dim i As Integer
vs = "1234567890." vo = "()*/+-#"
ConMax = 3 Contrast(1) = "x" Contrast(2) = "y" Contrast(3) = "z" OrgExp = "x*y+z*2*(y-z)/3" For i = 1 To ConMax Value(i) = InputBox(OrgExp & vbCrLf & "请输入变量" & Contrast(i) & "所代表的值", , 0) Next i PreScan OrgExp, E(), Emax
'MsgBox "总共发现" & Emax & "个关键字" OrgExp = OrgExp & vbCrLf & vbCrLf For i = 1 To ConMax OrgExp = OrgExp & Contrast(i) & "=" & Value(i) & vbCrLf Next i OrgExp = OrgExp & vbCrLf
For i = 0 To Emax - 1 If E(i).a = EXP_OPR Then OrgExp = OrgExp & Mid(vo, E(i).v - 1, 1) & " " Else OrgExp = OrgExp & E(i).v & " " End If Next i
MsgBox OrgExp & " = " & vbCrLf & Calculate(E(), Emax) End SubSub PreScan(ByVal str As String, ByRef E() As ExpType, ByRef Emax As Integer) Dim i As Integer, j As Integer, l As Integer Emax = 0 str = str & "#" l = Len(str) i = 1 Do For j = 1 To ConMax If Mid(str, i, Len(Contrast(j))) = Contrast(j) Then '变量 E(Emax).a = EXP_VAL E(Emax).v = Value(j) Emax = Emax + 1 i = i + Len(Contrast(j)) Exit For End If Next j If InStr(1, vs, Mid(str, i, 1)) > 0 Then '操作数 For j = i + 1 To Len(str) If InStr(j, vs, Mid(str, j, 1)) <= 0 Then Exit For End If Next j E(Emax).a = EXP_VAL E(Emax).v = Val(Mid(str, i, j - i + 1)) Emax = Emax + 1 i = j ElseIf InStr(1, vo, Mid(str, i, 1)) > 0 Then '运算符 E(Emax).a = EXP_OPR E(Emax).v = InStr(1, vo, Mid(str, i, 1)) + 1 'v\2=运算级别 i = i + 1 Emax = Emax + 1 Else MsgBox "表达式错误!" & vbCrLf & str & vbCrLf & "POS:" & i Exit Do End If Loop While i <= l End SubFunction Calculate(E() As ExpType, Emax As Integer) As Double 'x + ( y - z ) * num Dim i As Integer Dim a As Double, b As Double, c As Double, d As Integer
i = 0 Do If E(i).a = EXP_VAL Then v(vp) = E(i).v vp = vp + 1 i = i + 1 Else Select Case pri(o(op - 1), E(i).v) Case 0 o(op) = E(i).v op = op + 1 i = i + 1 Case 1 If o(op - 1) = 8 And E(i).v = 8 Then Exit Do ElseIf o(op - 1) = 3 And o(op - 2) = 2 Then op = op - 2 Else
a = v(vp - 2) b = v(vp - 1) Select Case o(op - 1) Case 4 ' * a = a * b Case 5 ' / a = a / b Case 6 ' + a = a + b Case 7 ' - a = a - b End Select vp = vp - 1 op = op - 1 v(vp - 1) = a End If Case Else MsgBox "ERROR" Stop End Select End If Loop While True Calculate = v(0) End Function
模块代码:
'计算用户输入的表达式
'如 "3+2*2" 结果为 "7"Public Function 计算(GS As String) As String
Dim i, n As Integer
Dim TempGs, Temp As String
Dim Vl() As String '操作数
Dim Vls As Integer '操作数的数目
Dim Si As Integer '上一操作符的位置
Dim Ads, Sus, Mus, Bys, Lks, Rks As Integer '操作符的数目
Dim Adp(), Mup(), Byp(), Lkp(), Rkp() As Integer '操作符的位置
Dim Adn(), Mun(), Byn() As Integer '操作符的排列次序
Dim Sig() As Integer '每一个操作符的位置
On Error GoTo Err
Do While True
ReDim Adp(Len(GS)), Mup(Len(GS)), Byp(Len(GS)) _
, Lkp(Len(GS)), Rkp(Len(GS)) As Integer
ReDim Adn(Len(GS)), Mun(Len(GS)), Byn(Len(GS)) _
, Lkn(Len(GS)), Rkn(Len(GS)), Sig(Len(GS)) As Integer
ReDim Vl(Len(GS))
If Len(GS) = 0 Then GoTo Err
If Mid(GS, Len(GS), 1) <> "#" Then
TempGs = GS
For i = 1 To Len(GS) '将减化加
If Mid(GS, i, 1) = "-" And i <> 1 Then
If Mid(GS, i - 1, 1) <> "+" And Mid(GS, i - 1, 1) <> "-" _
And Mid(GS, i - 1, 1) <> "*" And Mid(GS, i - 1, 1) <> "/" Then
TempGs = Mid(TempGs, 1, i - 1 + n) + "+" + Mid(GS, i)
n = n + 1
End If
End If
Next i
GS = TempGs
n = 0
For i = 1 To Len(GS) '处理负负得正
If Mid(GS, i, 1) = "-" Then
If Mid(GS, i + 1, 1) = "-" Then
TempGs = Mid(TempGs, 1, i - 1 - n) + Mid(GS, i + 2)
n = n + 2
End If
End If
Next i
GS = TempGs
GS = GS + "#"
End If
Vls = 1
Ads = 0: Sus = 0: Mus = 0: Bys = 0: Lks = 0: Rks = 0
For i = 1 To Len(GS)
Select Case Mid(GS, i, 1)
Case "+"
Ads = Ads + 1
Adp(Ads) = i
Adn(Ads) = Vls
Case "*"
Mus = Mus + 1
Mup(Mus) = i
Mun(Mus) = Vls
Case "/"
Bys = Bys + 1
Byp(Bys) = i
Byn(Bys) = Vls
Case "("
Lks = Lks + 1
Lkp(Lks) = i
Case ")"
Rks = Rks + 1
Rkp(Rks) = i
End Select
If Mid(GS, i, 1) = "+" Or Mid(GS, i, 1) = "*" Or _
Mid(GS, i, 1) = "/" Or Mid(GS, i, 1) = "#" Then
If Si + 1 = i And Mid(GS, i + 1, 1) <> "#" _
Then '操作符非法连续或以操作符开头
GoTo Err
Else
Si = i
End If
If Not IsNumeric(Vl(Vls)) And Mid(GS, i + 1, 1) <> "#" _
Then '操作数不是数字
GoTo Err
End If
Sig(Vls) = i
Vls = Vls + 1
Else
If Mid(GS, i, 1) <> "(" And Mid(GS, i, 1) <> ")" Then
Vl(Vls) = Vl(Vls) + Mid(GS, i, 1) '制作操作数
Else
If i <> 1 Then
If ((Mid(GS, i - 1, 1) = "(" And Mid(GS, i, 1) = ")") Or _
(Mid(GS, i - 1, 1) = ")" And Mid(GS, i, 1) = "(")) _
Then '判定括号前后符号的合法性
GoTo Err
End If
End If
End If
End If
Next i
If Lks <> Rks Then
GoTo Err '左右括号数是否匹配
End If
For i = 1 To Lks
If Lkp(i) > Rkp(i) Then GoTo Err '左右括号出现顺序错误
Next i
If Lks <> 0 Then '括号处理
Do While True
For i = Lks To 1 Step -1
For n = Rks To 1 Step -1
Temp = 计算(Mid(GS, Lkp(i) + 1, Rkp(n) - Lkp(i) - 1))
If Temp <> "公式有错误" Then
GS = Mid(GS, 1, Lkp(i) - 1) + Temp + Mid(GS, Rkp(n) + 1)
Exit Do
End If
Next n
Next i
If Temp = "公式有错误" Then GoTo Err
'括号中有错误退出
Loop
Else
If Mus <> 0 Then '乘法处理
GS = Mid(GS, 1, Sig(Mun(1) - 1)) + Trim(Str(Val(Vl(Mun(1))) _
* Val(Vl(Mun(1) + 1)))) + Mid(GS, Val(Mup(1)) + Len(Vl(Mun(1) _
+ 1)) + 1)
Else
If Bys <> 0 Then '除法处理
GS = Mid(GS, 1, Sig(Byn(1) - 1)) + Trim(Str(Val(Vl(Byn(1))) _
/ Val(Vl(Byn(1) + 1)))) + Mid(GS, Val(Byp(1)) + Len(Vl(Byn(1) _
+ 1)) + 1)
Else
If Ads <> 0 Then '加法处理
GS = Trim(Str(Val(Vl(1)) + Val(Vl(2)))) + Mid(GS, Val(Adp(1)) _
+ Len(Vl(2)) + 1)
Else
计算 = Mid(GS, 1, Len(GS) - 1)
Exit Function
End If
End If
End If
End If
Loop
Err:
计算 = "公式有错误"
End Function
首先把x,y,z,+,-,*,(,),num提取出来,建立表达式树,然后计算。
如果xy都用变量表示,你还写一个函数干吗?
需要怎么计算,直接写就可以啦,就象 Leftie(Leftie) 写的那样!
'(C)LengDakun
'表达式计算
'1、变量识别
'2、表达式构建
'3、计算
'
'建立变量标识对照,建立逆波兰表达式。
' 表达式由数字,变量,运算符组成
'定义:运算符:+,-,*,/,(,)
' 运算优先级别:(, ), */, +-
Type ExpType
a As Integer 'Attribute of a word
v As Double 'Value of a word
End TypeConst EXP_NONE = 0 'None
Const EXP_VAL = 1 'Value
'Const EXP_VAR = 2 'Variable
Const EXP_OPR = 3 'OperatorPrivate Contrast(1 To 128) As String, ConMax As Integer
Private Value(1 To 128) As Double
Private vs As String, vo As StringSub Main()
Dim OrgExp As String
Dim E(255) As ExpType, Emax As Integer
Dim i As Integer
vs = "1234567890."
vo = "()*/+-#"
ConMax = 3
Contrast(1) = "x"
Contrast(2) = "y"
Contrast(3) = "z"
OrgExp = "x*y+z*2*(y-z)/3"
For i = 1 To ConMax
Value(i) = InputBox(OrgExp & vbCrLf & "请输入变量" & Contrast(i) & "所代表的值", , 0)
Next i
PreScan OrgExp, E(), Emax
'MsgBox "总共发现" & Emax & "个关键字"
OrgExp = OrgExp & vbCrLf & vbCrLf
For i = 1 To ConMax
OrgExp = OrgExp & Contrast(i) & "=" & Value(i) & vbCrLf
Next i
OrgExp = OrgExp & vbCrLf
For i = 0 To Emax - 1
If E(i).a = EXP_OPR Then
OrgExp = OrgExp & Mid(vo, E(i).v - 1, 1) & " "
Else
OrgExp = OrgExp & E(i).v & " "
End If
Next i
MsgBox OrgExp & " = " & vbCrLf & Calculate(E(), Emax)
End SubSub PreScan(ByVal str As String, ByRef E() As ExpType, ByRef Emax As Integer)
Dim i As Integer, j As Integer, l As Integer
Emax = 0
str = str & "#"
l = Len(str)
i = 1
Do
For j = 1 To ConMax
If Mid(str, i, Len(Contrast(j))) = Contrast(j) Then '变量
E(Emax).a = EXP_VAL
E(Emax).v = Value(j)
Emax = Emax + 1
i = i + Len(Contrast(j))
Exit For
End If
Next j
If InStr(1, vs, Mid(str, i, 1)) > 0 Then '操作数
For j = i + 1 To Len(str)
If InStr(j, vs, Mid(str, j, 1)) <= 0 Then
Exit For
End If
Next j
E(Emax).a = EXP_VAL
E(Emax).v = Val(Mid(str, i, j - i + 1))
Emax = Emax + 1
i = j
ElseIf InStr(1, vo, Mid(str, i, 1)) > 0 Then '运算符
E(Emax).a = EXP_OPR
E(Emax).v = InStr(1, vo, Mid(str, i, 1)) + 1 'v\2=运算级别
i = i + 1
Emax = Emax + 1
Else
MsgBox "表达式错误!" & vbCrLf & str & vbCrLf & "POS:" & i
Exit Do
End If
Loop While i <= l
End SubFunction Calculate(E() As ExpType, Emax As Integer) As Double
'x + ( y - z ) * num
Dim i As Integer
Dim a As Double, b As Double, c As Double, d As Integer
Dim pri(2 To 16, 2 To 16) As Integer
Dim v(0 To 255) As Double, vp As Integer '操作数堆栈
Dim o(0 To 255) As Integer, op As Integer '运算符堆栈
'
' ( ) * / + - #
' 2 3 4 5 6 7 8
' ( 2 < < < < < < !
' ) 3 ! > > > > > >
' * 4 < > > > > > >
' / 5 < > > > > > >
' + 6 < > < < > > >
' - 7 < > < < > > >
' # 8 < < < < < < <
'
pri(2, 2) = 0: pri(2, 3) = 0: pri(2, 4) = 0: pri(2, 5) = 0: pri(2, 6) = 0: pri(2, 7) = 0: pri(2, 8) = -1
pri(3, 2) = -1: pri(3, 3) = 1: pri(3, 4) = 1: pri(3, 5) = 1: pri(3, 6) = 1: pri(3, 7) = 1: pri(3, 8) = 1
pri(4, 2) = 0: pri(4, 3) = 1: pri(4, 4) = 1: pri(4, 5) = 1: pri(4, 6) = 1: pri(4, 7) = 1: pri(4, 8) = 1
pri(5, 2) = 0: pri(5, 3) = 1: pri(5, 4) = 1: pri(5, 5) = 1: pri(5, 6) = 1: pri(5, 7) = 1: pri(5, 8) = 1
pri(6, 2) = 0: pri(6, 3) = 1: pri(6, 4) = 0: pri(6, 5) = 0: pri(6, 6) = 1: pri(6, 7) = 1: pri(6, 8) = 1
pri(7, 2) = 0: pri(7, 3) = 1: pri(7, 4) = 0: pri(7, 5) = 0: pri(7, 6) = 1: pri(7, 7) = 1: pri(7, 8) = 1
pri(8, 2) = 0: pri(8, 3) = 0: pri(8, 4) = 0: pri(8, 5) = 0: pri(8, 6) = 0: pri(8, 7) = 0: pri(8, 8) = 1
op = 1
o(0) = InStr(1, vo, "#") + 1
vp = 0
i = 0
Do
If E(i).a = EXP_VAL Then
v(vp) = E(i).v
vp = vp + 1
i = i + 1
Else
Select Case pri(o(op - 1), E(i).v)
Case 0
o(op) = E(i).v
op = op + 1
i = i + 1
Case 1
If o(op - 1) = 8 And E(i).v = 8 Then
Exit Do
ElseIf o(op - 1) = 3 And o(op - 2) = 2 Then
op = op - 2
Else
a = v(vp - 2)
b = v(vp - 1)
Select Case o(op - 1)
Case 4 ' *
a = a * b
Case 5 ' /
a = a / b
Case 6 ' +
a = a + b
Case 7 ' -
a = a - b
End Select
vp = vp - 1
op = op - 1
v(vp - 1) = a
End If
Case Else
MsgBox "ERROR"
Stop
End Select
End If
Loop While True
Calculate = v(0)
End Function
将表达式写入OrgExp字符串,然后调用PreScan()翻译表达式,利用Calculate()计算数值。Calculate()中的pri()数组为运算符优先级表格。需要增加算符的时候请更改vo变量内容和pri()数组,注意不要改变原先运算符的位置。尤其是结束符#的位置。