ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] 一个通用的EXCEL工程量计算表

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-5-13 18:14 | 显示全部楼层
本帖最后由 cbtaja 于 2016-5-21 08:56 编辑

再次更新求值函数:
  1. Function XEVAL(ByVal exp As String) '作者cbtaja 2016-5-13
  2.     If Len(exp) = 0 Then XEVAL = "": Exit Function
  3.     exp = ExpClean(exp)
  4.     If Len(exp) = 0 Then XEVAL = "": Exit Function
  5.     If Len(Replace(exp, "(", "")) - Len(Replace(exp, ")", "")) Then XEVAL = "括号不成对": Exit Function
  6.     XEVAL = mEval(exp) '对Exp分步计算,可以应对超长的Exp计算式
  7. '    XEVAL = Evaluate(exp)'如果exp的长度总是不超过255,则可以用Evaluate简化计算过程。
  8. '    If IsError(XEVAL) Then XEVAL = EvalErrInfo(CStr(XEVAL)) & Exp
  9. End Function

  10. Function EvalErrInfo(ByVal exp As String)
  11.     Select Case CStr(exp)
  12.         Case "Error 2000": EvalErrInfo = "缺少参数:"
  13.         Case "Error 2007": EvalErrInfo = "除数为○:"
  14.         Case "Error 2015": EvalErrInfo = "参数类型不符:"
  15.         Case "Error 2023": EvalErrInfo = "单元格引用无效:"
  16.         Case "Error 2029": EvalErrInfo = "函数名无效:"
  17.         Case "Error 2036": EvalErrInfo = "参数超出范围:"
  18.         Case "Error 2042": EvalErrInfo = "参数无效:"
  19.         Case Else:
  20.     End Select
  21. End Function

  22. Function ExpClean$(ByVal exp As String)
  23.     Set reg = CreateObject("VBScript.RegExp")
  24.     reg.Global = True
  25.     reg.Pattern = "\[[^\]\[]*\]" '忽略计算式中的[注释内容]
  26.     exp = reg.Replace(exp, "")
  27.     a = [{"+","+";"-","-";"×","*";"÷","/";"(","(";")",")";"%","*0.01"}] '“兼容”中文数学运算符'
  28.     For i = 1 To UBound(a)
  29.         reg.Pattern = a(i, 1)
  30.         exp = reg.Replace(exp, a(i, 2))
  31.     Next
  32.     If InStr(exp, "[") Or InStr(exp, "]") Then ExpClean = "[]不成对": Exit Function
  33.     reg.Pattern = "[^\x20-\x7e]+" '仅保留“基本拉丁字符”
  34.     ExpClean = reg.Replace(exp, "")
  35. End Function

  36. Function sEval(ByVal exp As String)
  37.     exp = UCase(exp)
  38.     Set reg = CreateObject("VBScript.RegExp")
  39.     reg.Global = False
  40.     sPttnNumber = "\d+(\.\d+){0,1}(E[+-]\d+(\.\d+){0,1}){0,1}" '数值(含整数、小数、科学计数法表示的数值)
  41.     sPttnCalChar = [{"\^","[\*\/]","[\+\-]"}] '依次进行乘幂、乘除、加减运算
  42.     For i = 1 To UBound(sPttnCalChar)
  43.         reg.Pattern = "(?:\b)" & sPttnNumber & sPttnCalChar(i) & sPttnNumber
  44.         Do While reg.test(exp)
  45.             Set matches = reg.Execute(exp)
  46.             tmp = matches(0)
  47.             sEval = Evaluate(tmp)
  48.             If IsError(sEval) Then sEval = EvalErrInfo(CStr(sEval)) & tmp: Exit Function
  49.             exp = reg.Replace(exp, sEval)
  50.             If Len(exp) <= 255 Then Exit Do
  51.         Loop
  52.     Next
  53.    
  54.     'Evaluate("1") 无法计算,所以按条件处理为两次求反
  55.     If Len(exp) = 1 Then sEval = Evaluate("--" & exp) Else sEval = Evaluate(exp)
  56.    
  57.     If IsError(sEval) Then sEval = EvalErrInfo(CStr(sEval)) & exp
  58. End Function

  59. Function mEval(ByVal exp As String)
  60.     Set reg = CreateObject("VBScript.RegExp")
  61.     reg.Global = True
  62.     reg.Pattern = "\w+(\([^\(\)]*\))"
  63.     Do While reg.test(exp)
  64.         Set matches = reg.Execute(exp)
  65.         For i = matches.Count To 1 Step -1
  66.             mEval = sEval(matches(i - 1).Value)
  67.             If Not IsNumeric(mEval) Then Exit Function
  68.             exp = reg.Replace(exp, mEval)
  69.         Next
  70.     Loop
  71.     mEval = sEval(exp)
  72. End Function

  73. Function XEval(ByVal Exp As String) '作者cbtaja 2016-5-13
  74.     '自动转换中文运算符+-×÷
  75.     '允许百分号%和科学计数符号e
  76.     '允许数学函数(要以前缀m.或Math.作标记,注意名称和参数类型要正确)
  77.     '允许中文直接注释,
  78.     '允许用成对中括号(即[])包含任意注释字符,
  79.     '剩余不成对的中括号"["、"]"将被忽略
  80.     '最后,如果算式仍无法计算,则报告出错的变量
  81.     '------------------------------------------------
  82.     Dim oJs As Object, XX As String, errinfo, a, i&
  83.     Set oJs = CreateObject("ScriptControl")
  84.     oJs.Language = "JScript"
  85.     Exp = oJs.eval("'" & Exp & "'.replace(/\[[^\]\[]*\]/g,"""")") '清除成对中括号[]及其中的内容
  86.     If IsEmpty(Exp) Then Exit Function
  87.    
  88.     a = [{"+","+";"-","-";"×","*";"÷","/";"[","";"]","";"%","*0.01"}] '替换不规范的运算符
  89.     For i = 1 To UBound(a)
  90.         Exp = Replace(Exp, a(i, 1), a(i, 2))
  91.     Next
  92.     If IsEmpty(Exp) Then Exit Function
  93.    
  94.     Exp = oJs.eval("'" & Exp & "'.replace(/[^\x21-\x7e]/g,"""")") '仅保留ASC码为33至125之间的字符
  95.     If IsEmpty(Exp) Then Exit Function
  96.    
  97.     Exp = oJs.eval("'" & Exp & "'.replace(/\bm\./ig,""Math."")") '把“m.”(或“M.”)替换为“Math.”,以支持Js的数学函数
  98.     If IsEmpty(Exp) Then Exit Function
  99.    
  100.     On Error GoTo errhdl
  101.     XEval = oJs.eval(Exp) '对经过整理后的计算式进行求值
  102.     If IsEmpty(XEval) Then GoTo errhdl
  103.     XX = CStr(XEval)
  104.    
  105.     For Each errinfo In Array("R", "IND", "INF", "QNAN", "SNAN")
  106.         If InStr(XX, ".#" & errinfo) Then GoTo errhdl
  107.     Next
  108.     Exit Function
  109. errhdl:
  110.     XEval = "请修正:" & Trim(oJs.eval("'" & Exp & "'.replace(/[^\w.\/]+/ig,"""")"))
  111. End Function
复制代码


用JSCript的EVAL方法,也可以做很多事情:
  1. Function ev(ByVal s As String)
  2.     Set oJs = CreateObject("ScriptControl")
  3.     oJs.Language = "JScript"
  4.     ev = oJs.eval(s)
  5. End Function
  6. Private Sub cs()
  7. Dim sss(0 To 9)
  8. sss(0) = "(2,Math.PI/2)"
  9. sss(1) = "小黄的数学考试得了95分,评价为A;语文得了92分,评价为B+,他的父亲奖励了他一双价值888.88元的轮滑鞋。"
  10. sss(2) = "2+Math.sin(Math.PI/4)"
  11. aaa = ev(sss(0)) '数学函数式求值
  12. MsgBox aaa
  13. aaa = ev("'" & sss(1) & "'.replace(/[\s\u3400-\ufe4f]+/ig,"" "")") '文本正则替换
  14. MsgBox aaa
  15. aaa = ev(sss(2)) '数学函数式求值
  16. MsgBox aaa
  17. aaa = ev("'" & sss(1) & "'.length") '求字符串长度
  18. MsgBox aaa
  19. aaa = ev("'" & sss(1) & "'.substr(3,9)") '取子符串(类似于VB的mid函数)
  20. MsgBox aaa
  21. aaa = ev("Math.e") '
  22. MsgBox aaa
  23. aaa = ev("Math.E") '自然对数的底E。要注意:Script中的变量名是区分大小写的。
  24. MsgBox aaa
  25. '通过构造语句,以JSCript的EVAL方法解释执行语句,可以完成很多事情。(只要熟知JSCript的内置对象的属性、方法、函数就好办)
  26. Stop
  27. End Sub
复制代码

  1. Function RegReplace(ByVal s As String, ByVal patn As String, Optional ByVal delemit As String = "")
  2.     '中文:"[\u3400-\ufe4f]"
  3.     '数字:"[\d]"或"[0-9]"
  4.     '数值:"\d+(\.\d+|)(e[+-]\d+)?%?"
  5.     '字母:"[a-zA-Z]"
  6.     Set reg = CreateObject("vbscript.Regexp")
  7.     reg.Global = True
  8.     reg.Pattern = patn
  9.     RegReplace = reg.Replace(s, delemit)
  10. End Function
复制代码

补充内容 (2016-7-4 21:47):
求值函数更新,修正1处Bug,请从23楼下载附件中查看。

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-5-22 08:22 | 显示全部楼层
本帖最后由 cbtaja 于 2016-7-6 19:00 编辑

更新内容:2016-5-22
1、更新计算式求值函数:①突破255字符数上限限制,②可在64位EXCEL中正常运行,③、当计算式不能计算出结果时,提示信息更加全面:可以精确提示错误发生的部位和原因!
2、“代号”输入或计算其计算式时,自动检测并提示命名不合格的“代号”。
3、汇总计算时自动检测提示重复的代号名称。
4、增加对所有自动宏的开关(当不需要自动提示或计算功能时,可以关闭自动宏,专注于表格数据输入,且可避免自动宏影响撤消功能。)
5、自动汇总,取消原来的VBA+数据透视表方式,采用VBA数组+字典方式,运算更快速、所得汇总表的版面也更整洁。
如使用64位EXCEL,类模块中的代码需要替换如下部分API声明:
  1. Private Declare PtrSafe Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
  2.         (Destination As Any, Source As Any, ByVal Length As Long)
  3.         
  4. Private Declare PtrSafe Function CLSIDFromString Lib "ole32.dll" _
  5.         (ByVal lpszProgID As Long, pCLSID As GUID) As Long
  6.         
  7. Private Declare PtrSafe Function CoCreateInstance Lib "ole32" ( _
  8.         rclsid As GUID, ByVal pUnkOuter As Long, _
  9.         ByVal dwClsContext As Long, riid As GUID, _
  10.         ByRef ppv As Long) As Long

  11. Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" _
  12.         (ByVal pvInstance As Long, ByVal oVft As Long, _
  13.         ByVal cc As Long, ByVal vtReturn As Integer, _
  14.         ByVal cActuals As Long, prgvt As Integer, _
  15.         prgpvarg As Long, pvargResult As Variant) As Long

  16. Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32" (pv As Long)
复制代码


工程量计算表.rar

693.84 KB, 下载次数: 268

TA的精华主题

TA的得分主题

发表于 2016-6-4 13:32 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2016-6-26 20:49 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
太棒了!谢谢楼主的分享!

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-7-6 20:47 | 显示全部楼层
本帖最后由 cbtaja 于 2016-7-19 19:03 编辑

工程量计算表.rar (580.19 KB, 下载次数: 306) 1、更新计算式自动求值函数:

      ①、完美支持EXCEL所有内置函数及当前可用的自定义函数;
      ②、支持用【代号】引用计算式结果的功能;
      ③、支持单元格引用;
      ④、注释内容可自动突出显示:即可自动下标且变色。且该功能可随时开关。注释内容的分析更加精准:被成对引号包含的内容,被优先解释为公式中的“字符串”常量参数,终于可以如同EXCEL公式一样地能正确计算Text(Day(today())-11,"[>9]下旬;上旬;中旬") 这样的算式了!

现在可以算是几乎完全达成开贴时的几个目标了:
1、计算式自动求值,可包含注释,且注释可自动地以下标形式突出显示;
2、计算式支持用“代号”引用计算结果;
3、在输入分项名称时,能自动匹配内置小型的(定额)数据库,并能 逐步提示 + 自动完成,以人为本的完美体验;
4、对工程量清单实现一键自动汇总功能;
5、计算稿和汇总表的表格边框都可自动添加或消除,省去手工设置的麻烦
6、预设了合理的页面设置,其中默认打印表格行号列标,这样当在计算式中直接引用单元格名称时,可以直观对应相应的数值,比自己编写代号更灵活。

        最后,如果还有兴趣继续的话,可能考虑的升级方向有:
        1、增加对常见特殊形状或结构的工程量计算公式的图形化辅助输入,可方便土建的混凝土、土方、沟渠等体积计量,装饰、粉刷、油漆等面积计量,钢筋等长度计量,以及安装工程中电缆、管线、钢结构等的主材用量计算公式;另外,可考虑由用户自行扩充该图形辅助公式库的功能;
        2、把EXCEL内置定额库可改为外部ACCESS数据库,可减少模板文件体积,方便更换定额。
        如果再完成这些的话,基本上就达到表格算量软件其所能提供的帮助的极限了。
       现在四维算量软件普及化,但表格算量仍以其灵活性、对数据本身的直接操作和结果呈现形式而占有相当份额的市场。而且,相对于工程预算员的人数,工程施工技术员的人数更多。后者在做材料计划时,所使用的一般不会是各种图形算量软件,而往往是自己所熟练操作的电子表格软件。本表格模板也算是一个小小的贡献吧

TA的精华主题

TA的得分主题

发表于 2016-7-17 18:26 | 显示全部楼层
下载了,试了一下,输入计算式没见反应,还是我不会用

TA的精华主题

TA的得分主题

发表于 2016-8-26 16:12 | 显示全部楼层
楼主 能不能有在win10系统64位下可用的,谢谢!

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-8-29 03:55 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
kfhgng 发表于 2016-8-26 16:12
楼主 能不能有在win10系统64位下可用的,谢谢!

25楼的附件,可以在64位和32位的excel中通用的,只需要启用宏即可。至于26楼所说,输入计算式后没有反应,可能是在程序的“批量设置”中关闭了“启用自动宏”功能,只需要执行“批量设置”宏,勾选“启用自动宏”即可。

TA的精华主题

TA的得分主题

发表于 2016-8-29 07:54 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
收下了 谢谢分享!

TA的精华主题

TA的得分主题

发表于 2016-9-1 16:30 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
楼主,对于撤销功能失效的问题可以解决吗?
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-16 19:46 , Processed in 0.044286 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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