ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 11394|回复: 25

[分享] 解决Evaluate函数超过255字符的方法之一

[复制链接]

TA的精华主题

TA的得分主题

发表于 2017-11-25 02:51 | 显示全部楼层 |阅读模式
本帖最后由 岁月无恒 于 2017-11-27 15:10 编辑

    EVALUATE宏表函数,是表达式计算的最常用函数之一,此函数功能强大,支持excel内置函数、支持分行计算、使用方便,表达式计算的首选函数。
    但是,这个函数存在表达式字符的长度限制,超过255个字符。计算结果就会显示错误,导致无法使用。论坛里提供过其他的解决方法,或多或少存在些缺陷,比如使用不方便、需要库的支持、不支持excel内置函数等等。
    我提供的方案,或许是最笨的方法,实现了我工作使用的要求,不受字符长度限制、可以用内置函数等,解决方案为:利用四则混合运算法则,把字符数超过限制的表达式(使用EVALUATE函数),先进行运算级别最高的括号运算→用计算结果生成新的没有括号的表达式→再把除加减外的运算全部计算(加减的运算级别最低留最后,乘除、乘方的计算顺序,由excel自己判断,我只把相关计算式提取出来)→再把运算结果重新生成只有加减运算的表达式→最后使用EVALUATE函数输出表达式结果,这样就间接的减少了表达式的长度,实现了计算要求。
    代码写得不够精简,请各位见谅,如有需要,欢迎使用。使用中出现了问题,请及时留言反馈。


测试.rar (16.22 KB, 下载次数: 159)

  1. Function MyVlaue(Rng As Range, Optional Point As Integer = 3) As Variant
  2. Dim 计算式 As String, Tmp As String

  3. '=====================================计算式整理=====================================
  4. '计算式中可以用中括号、大括号,使计算式更为直观,以便做检查计算式

  5. Tmp = Application.Clean(StrConv(Rng, vbNarrow))             '全角转半角,清不可见字符
  6. Tmp = Application.Substitute(Tmp,  , )                  '清除计算式中的空格
  7. Tmp = Replace(Replace(Tmp, (, (), ), ))           '中文括号转换为英文括号
  8. Tmp = Replace(Replace(Tmp, [, (), ], ))             '中括号转换为小括号
  9. Tmp = Replace(Replace(Tmp, {, (), }, ))             '大括号转换为小括号
  10. Tmp = Replace(Replace(Tmp, ×, ), ÷, )           '乘号、除号转换为计算符号

  11. '===================================清除计算式的注释===================================
  12. '注释内容一定要用【】标记,否侧会影响后面的判断

  13. Dim i As Integer, j As Integer
  14. For j = 1 To Len(Tmp)
  15.     If Mid(Tmp, j, 1) = 【 Then
  16.        For i = j + 1 To Len(Tmp)
  17.            If Mid(Tmp, i, 1) = 】 Then
  18.               j = i + 1
  19.               Exit For
  20.            End If
  21.         Next
  22.     End If
  23.     计算式 = 计算式 & Mid(Tmp, j, 1)
  24. Next

  25. '======================================整理式计算======================================
  26. '如果计算式长度少于等于255字符,则跳过此步,直接进结果计算
  27. '如果计算式长度大于255字符,则按照四则运算法则:函数公式→括号→乘除→加减顺序
  28. '如果计算式中存在函数,函数的括号会影响括号的计算,需要先把函数公式转换成结果
  29. '再判断“+”、“-”号的位置,把相邻“+”、“-”号之间的计算式(乘除等运算)转换为结果
  30. '判断得到的纯加减运算式的长度,若小于等于255字符,直接结算结果;若大于于255字符,再进行简化

  31. If Len(计算式) > 255 Then           '如果计算式字符数小于等于255,则跳过此步

  32.   '先把公式中引用的定义名称转换成数值,以免名称中的字母影响函数的判断
  33.    Dim Na, s As Integer
  34.    Set Na = ActiveWorkbook.Names
  35.    For s = 1 To Na.Count
  36.        If InStr(计算式, Na(s).Name)  0 Then
  37.           计算式 = Application.Substitute(计算式, Na(s).Name, Evaluate(Na(s).Name))
  38.        End If
  39.    Next

  40.   '判断计算式中是否存在函数,若存在,先依次计算函数(以免函数中的括号影响下一步括号计算)
  41.    Dim TmpStr1$, TmpValue1 As Double
  42.    Dim a%, b%, c%, d%, e%  '计数器
  43.    
  44.    For a = 1 To Len(计算式) - 2
  45.        If Mid(计算式, a, 1) Like [A-Z] Or Mid(计算式, a, 1) Like [a-z] Then   '出现字母,表示出现了函数
  46.       
  47.          '判断函数嵌套了几层
  48.           Do
  49.              b = b + 1
  50.              If Mid(计算式, a + b, 1) = ( Then
  51.                 c = c + 1
  52.              End If
  53.           Loop Until Mid(计算式, a + b, 1) = ) Or InStr(+-, Mid(计算式, a + b, 1))  0
  54.       
  55.          '计算函数结束位置
  56.           Do
  57.             d = d + 1
  58.             If Mid(计算式, a + d, 1) = ) Then
  59.                e = e + 1
  60.             End If
  61.           Loop Until e = c
  62.       
  63.          '提取函数公式部分计算式
  64.           TmpStr1 = Mid(计算式, a, d + 1)
  65.           TmpValue1 = Evaluate(TmpStr1)
  66.           计算式 = Application.Substitute(计算式, TmpStr1, TmpValue1)  '把函数结果写入计算式
  67.           b = 0 c = 0 d = 0 e = 0    '计数器归零,以便下次使用
  68.         End If
  69.    Next
  70.    
  71.   '如果有括号,先计算括号内的内容
  72.    If VBA.InStr(计算式, ()  0 Then
  73.       Dim TmpValue2 As Double, TmpStr2$
  74.       Dim KaiShi%, JieShu%, ShuLiang%
  75.       
  76.       Do
  77.         JieShu = VBA.InStr(计算式, ))
  78.         ShuLiang = Len(Mid(计算式, 1, JieShu)) - Len(Application.Substitute(Mid(计算式, 1, JieShu), (, ))
  79.         KaiShi = InStr(Application.Substitute(Mid(计算式, 1, JieShu), (, @, ShuLiang), @)
  80.         TmpStr2 = Mid(计算式, KaiShi, JieShu - KaiShi + 1)
  81.         TmpValue2 = Evaluate(TmpStr2)
  82.         计算式 = Application.Substitute(计算式, TmpStr2, TmpValue2)  '把括号结果写入计算式
  83.       Loop Until InStr(计算式, )) = 0
  84.    End If
  85.    
  86.   '如果有乘除,再从左往右依次算乘除
  87.    If VBA.InStr(计算式, ) + VBA.InStr(计算式, )  0 Then
  88.       Dim TmpValue3 As Double, TmpStr3$, Str3$
  89.       Dim x%, y%, z%
  90.       Dim Arr(1 To 1000)
  91.       Arr(1) = 0
  92.       For x = 1 To Len(计算式)
  93.           If InStr(+-, Mid(计算式, x, 1))  0 Then
  94.              y = y + 1
  95.              Arr(y + 1) = x
  96.           End If
  97.       Next
  98.       Arr(y + 2) = Len(计算式)
  99.       
  100.       For z = 1 To y + 1
  101.           If z = 1 Then
  102.              TmpStr3 = Mid(计算式, Arr(z) + 1, Arr(z + 1) - 1)
  103.           ElseIf z = y Then
  104.              TmpStr3 = Mid(计算式, Arr(z) + 1, Arr(z + 1) - Arr(z) - 1)
  105.           ElseIf z = y + 1 Then
  106.              TmpStr3 = Mid(计算式, Arr(z) + 1, Arr(z + 1) - Arr(z))
  107.              TmpValue3 = Evaluate(TmpStr3)
  108.              Str3 = Str3 & TmpValue3
  109.              Exit For
  110.           End If
  111.           TmpValue3 = Evaluate(TmpStr3)
  112.           Str3 = Str3 & TmpValue3 & Mid(计算式, Arr(z + 1), 1)
  113.       Next
  114.       
  115.    计算式 = Str3  '更新计算式
  116.    End If
  117.    
  118.   '若最后得到的计算式仍大于255字符,再进行简化,直到长度小于等于255字符
  119.    Dim TmpStr4$, TmpVlaue4 As Double
  120.    Dim m%, n%
  121.    If Len(计算式) > 255 Then
  122.       Do
  123.           Do
  124.              m = m + 1
  125.           Loop Until InStr(+-, Mid(计算式, 255 - m, 1))  0
  126.          
  127.           TmpStr4 = Mid(计算式, 1, 255 - m - 1)
  128.           TmpValue4 = Evaluate(TmpStr4)
  129.           计算式 = Application.Substitute(计算式, TmpStr4, TmpValue4)
  130.           m = 0
  131.       Loop Until Len(计算式) <= 255
  132.    End If
  133. End If

  134. '=======================================计算结果=======================================
  135. '如果计算式为空,则结果也为空
  136. '如果计算式有问题,计算结果显示“错”

  137. If Len(计算式) = 0 Then
  138.    MyVlaue =
  139. ElseIf VBA.IsError(Application.Evaluate(( & 计算式 & ))) Then   '若计算式有误,结果为错
  140.    MyVlaue = 错
  141. Else
  142.    MyVlaue = Application.Round(Application.Evaluate(( & 计算式 & )), Point)
  143. End If

  144. End Function
复制代码


评分

3

查看全部评分

TA的精华主题

TA的得分主题

发表于 2017-11-25 08:45 | 显示全部楼层
很简单,(1+2+...+100)就出错。现成的:
  1. Function F(S)
  2. With CreateObject("MSScriptControl.ScriptControl")
  3.   .Language = "vbscript"
  4.   F = .Eval(S)
  5. End With
  6. End Function
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2017-11-25 12:22 | 显示全部楼层
本帖最后由 岁月无恒 于 2017-11-25 13:30 编辑
Zamyi 发表于 2017-11-25 08:45
很简单,(1+2+...+100)就出错。现成的:

计算式中需要添加备注信息,这个确实可以不受字符数的限制,但是无法添加我要的备注信息。计算式比较长的时候,我要手动分行,手动分行后,这个函数也无法计算。
QQ截图20171125122214.jpg


TA的精华主题

TA的得分主题

发表于 2018-5-16 18:55 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
挺好用的,暂时没发现BUG。优化版的有么,大哥?

TA的精华主题

TA的得分主题

发表于 2018-5-17 14:37 | 显示全部楼层
1+1【备注1】【备注2】,这样有2个备注的时候就会出错

TA的精华主题

TA的得分主题

发表于 2018-5-17 14:53 | 显示全部楼层
1+1【备注】】  显示错
1+1【【备注】  就能计算

TA的精华主题

TA的得分主题

发表于 2018-5-18 16:39 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
楼主的去备注文字代码有误,重新代码如下:
'替换掉计算式中的[说明]
Do
If UBound(Split(jss, "[")) <> UBound(Split(jss, "]")) Then YJS = "括号错误": Exit Function
If InStr(jss, "[") > InStr(jss, "]") Then YJS = "括号错误": Exit Function
If InStr(jss, "[") = 0 Then Exit Do
jss = Left(jss, InStr(jss, "[") - 1) & Right(jss, Len(jss) - InStr(jss, "]"))
If InStr(jss, "]") = 0 Then Exit Do
Loop

TA的精华主题

TA的得分主题

发表于 2018-5-18 16:44 | 显示全部楼层
很好的思路,正是我想要的。解决了我的一个问题。
http://club.excelhome.net/thread-1375312-1-1.html

TA的精华主题

TA的得分主题

发表于 2018-5-18 17:43 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
不完美,有缺陷。不能计算max(超长计算式,超长计算式)这类内置函数

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-24 08:50 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
34682189 发表于 2018-5-18 16:39
楼主的去备注文字代码有误,重新代码如下:
'替换掉计算式中的[说明]
Do

谢谢提醒,我再测试下。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-16 13:27 , Processed in 0.040465 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表