四时宝库

程序员的知识宝库

Excel VBA 按数字加特定字符关键字汇总/正则表达式/字典

本文于2023年8月12日首发于本人同名公众号:Excel活学活用,更多文章案例请搜索关注!

内容提要

  • 正则表达式提取数字加指定字符
  • 字典方法汇总数据

大家好,我是冷水泡茶,今天在论坛上看到一个求助贴:

他的明细表数据是这样的:

他要在同一张表的B29、C29列写入数据:

他的具体需求是:把B列包含“??芯"项目,对应的G列数据进行汇总,并且用进一法舍入到10位,并且要把29行以下,C列为0的行删除。

其实,在实际工作中碰到类似问题,添加辅助列或者对照表都是不错的选择,但楼主不想添加辅助列,只想用VBA代码来解决,那么,从研究VBA代码的角度,还是值得探讨探讨的,我们一起来看一看吧:

基本思路

1、首先,我们分析关键字特征,它是不确定的几位数字加上一个“芯”。

2、然后,我又发现,它的项目字段中,只有一段连续的数字,没有其他数字。

3、我突然想起我们前面分享过的文章,正则表达式提取数字【Excel VBA 提取数字/自定义工作表函数/正则表达式/批量提取电话号码】,还有一篇【Excel VBA 提取单元格字符串中的数字并求和/兼聊原始数据的问题】。

4、我们用前文中分享过的函数GetNum把所有数字提取出来,再加上一个“芯”字,不就成了?试了一下,确实可行。但是感觉直接用这种方法,有点偷机取巧的意思,不算正解。

5、正确的思路应该是,用正则表达式把“芯”前面的数字及“芯”字提取出来。

程序代码

1、自定义函数ExtractKey,提取汇总关键字:

Function ExtractKey(str As String)
    Dim regex As Object
    Dim matches As Object
    Dim strResult As String
    ' 创建正则表达式对象
    Set regex = CreateObject("VBScript.RegExp")
    regex.Global = True
    regex.IgnoreCase = True
    regex.Pattern = "\d+芯"
    ' 执行正则匹配
    Set matches = regex.Execute(str)
    ' 提取第一个匹配结果
    If matches.Count > 0 Then
        strResult = matches.Item(0).Value
    Else
        strResult = ""
    End If
    ExtractKey = strResult
    ' 清除对象引用
    Set regex = Nothing
    Set matches = Nothing
End Function

?代码解析:

(1)创建正则表达式对象regex

(2)定义模式:regex.Pattern = "\d+芯",表示匹配“芯”及其前面的所有连续的数字。

(3)执行匹配Set matches = regex.Execute(str)

(4)提取匹配结果给自定义函数赋值

2、Sum过程,按提取关键字汇总数据:

Sub Sum()
    Dim arr()
    Dim ws As Worksheet
    Dim lastRow As Integer
    Dim Dic As Object
    Dim dKey As String
    Dim iCol As Integer
    Dim arrTem()
    ThisWorkbook.Activate
    Set ws = Sheets("线路定额")
    Set Dic = CreateObject("Scripting.dictionary")
    ws.Activate
    lastRow = 28
    arr = ws.Range(Cells(2, 2), Cells(lastRow, 7)).Value
    iCol = UBound(arr, 2)
    For i = 1 To UBound(arr, 1)
        If InStr(arr(i, 1), "芯") > 0 Then
            dKey = arr(i, 1)
            dKey = ExtractKey(dKey)
            Dic(dKey) = Dic(dKey) + arr(i, iCol)
        End If
    Next
    lastRow = ws.UsedRange.Rows.Count
    ws.Range("B29:C" & lastRow).ClearContents
    arrTem = Dic.keys
    ws.Range("B29").Resize(UBound(arrTem) + 1, 1) = Application.WorksheetFunction.Transpose(arrTem)
    arrTem = Dic.items
    '取整
    For i = LBound(arrTem) To UBound(arrTem)
        arrTem(i) = Application.WorksheetFunction.Ceiling(arrTem(i), 10)
    Next
    ws.Range("C29").Resize(UBound(arrTem) + 1, 1) = Application.WorksheetFunction.Transpose(arrTem)
    '删除C列单元格为0的行
    lastRow = ws.UsedRange.Rows.Count
    For i = lastRow To 29 Step -1
        If Cells(i, 3) = 0 Then
            Rows(i).Delete
        End If
    Next
End Sub

代码解析:

(1)定义字典Dic。

(2)把原始数据读入数组,他要求在第29行写入数据,所以把lastRow定为28。(我想不出原因为什么要在同一张表上进行汇总,要是我做的话,肯定是把汇总数据放到另外一张表上。)

(3)循环数组,提取汇总关键字“?芯”,这里用同一个变量dkey,逐步取得结果。

(4)把关键字装入字典,顺带进行汇总,把汇总结果存在字典的Item里。

(5)把字典的keys赋值给数组arrTem,再把arrTem存入工作表B列。

(6)把字典的items赋值给数组arrTem,用工作表函数ceiling把数组的值取整到10位后,再存入工作表C列。

(7)删除第29行以下,C列为0的记录。删除行要从下往上删除。

总结

1、字符提取,用正则表达式,非常方便。

2、字段汇总,用字典,可以在向字典添加键值的同时进行汇总。

---End---

喜欢就点个、点在看留个言呗!分享一下更给力!感谢!

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接