正则表达式应用示例

本节结合几个具体的场景介绍正则表达式在Excel数据处理中的应用。[大谦Excel,dqexcel点com]

应用示例1:计算各班的总人数

图8-3中处理前工作表中第2列的数据列出了各班成绩优秀、良好、中等、及格和不及格的人数,现要求根据这些人数计算出各班的总人数并写入第3列。

Document Image

图8-3 计算各班的总人数

观察后发现,工作表中B2-B4各单元格中的字符串,把数字前面的汉字及其后面的*号去掉后就剩下只有数字和加号的公式,计算该公式即得到各班的总人数。所以,问题的关键在于查找到这些汉字和*号,并删除它们。

【Excel VBA】

示例文件的存放路径为Samples\ch20\Excel VBA\计算各班的总人数.xlsm。

code.vba
Sub 正则01()
    Dim objReg As New RegExp
    Dim strTxt As String
    With objReg
      .Global = True  '全局查找
      .Pattern = "[\u4e00-\u9fa5]+\*"  '正则表达式,汉字后面跟*号
      '遍历B2-B4各单元格
      For Each c In Range([B2], Cells(Rows.Count, "B").End(xlUp))
        strTxt = .Replace(Trim(c.Value), "")  '删除匹配对象,剩下求和公式
        '计算求和公式,结果写入工作表指定位置
        c.Offset(0, 1).Value = Application.Evaluate(strTxt)
      Next
    End With
    Set objRegEx = Nothing
End Sub

运行过程,计算出各班的总人数并写入第3列,如图8-2中处理后工作表所示。

【Python】

本示例数据文件的存放路径为Samples\ch20\Python\计算各班的总人数.xlsx。本示例的py文件的存放路径为Samples\ch20\Python\计算各班的总人数..py。

code.python
import xlwings as xw  #导入xlwings包
import os  #导入os包
import re  #导入re包
root = os.getcwd()  #获取本py文件的当前路径
app = xw.App(visible=True, add_book=False)  #创建Excel应用,无工作簿
#打开当前路径上的数据文件,可写
wb=app.books.open(fullname=root+r"\计算各班的总人数.xlsx",read_only=False)
sht=wb.sheets(1)  #获取工作表
#获取B2-B4单元格区域中的数据
arr=sht.range("B2", sht.cells(sht.cells(1,"B").end("down").row, "B")).value
for i in range(len(arr)):  #遍历每行数据
    m=re.sub(r"[\u4e00-\u9fa5]+\*","",arr[i])  #中文和星号替换为空
    v=eval(str(m))  #剩下计算公式,计算结果
    sht.cells(i+2,3).value=v  #结果写入工作表

在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,计算出各班的总人数并写入第3列,如图8-2中处理后工作表所示。

应用示例2:整理食材数据

图8-4中处理前工作表中A1单元格中的数据为某次食材采购的记录,现要求整理成处理后工作表中第2列和第3列所示的比较整齐的形式。

Document Image

图8-4 用捕获分组整理数据

处理思路第1步是将各食材和它们的采购金额提取出来,在正则表达式中对食材名称和采购金额进行捕获分组,这样输出的时候可以将食材名称和采购金额用分组区分开来并分两列写入。

【Excel VBA】

示例文件的存放路径为Samples\ch20\Excel VBA\整理食材数据.xlsm。

code.vba
Sub reg25()
  Dim objReg As New RegExp  '生成正则对象
  Dim mcT As MatchCollection  '存放全部结果的集合
  Dim strT As String
  With objReg
    .Global = True  '全局查找
    '正则表达式,一个或多个汉字后面跟数字跟元,数字可带小数点
    '前面的汉字和后面的数据分别分组
    .Pattern = "([一-龢]{1,}) (\d+\.?\d*元)"
    strT = [A1]  '数据源
    Set mcT = .Execute(strT)  '执行查找
    For i = 0 To mcT.Count - 1  '遍历匹配结果
      Cells(i + 2, 2) = mcT(i).SubMatches(0)  '输出第1个分组,名称
      Cells(i + 2, 3) = mcT(i).SubMatches(1)  '输出第2个分组,数据
    Next
  End With
  Set objReg = Nothing
  Set mcT = Nothing
End Sub

运行过程,输出处理结果如图8-4中处理后工作表所示。

【Python】

本示例数据文件的存放路径为Samples\ch20\Python\整理食材数据.xlsx。本示例的py文件的存放路径为Samples\ch20\Python\整理食材数据..py。

code.python
import xlwings as xw  #导入xlwings包
import os  #导入os包
import re  #导入re包
root = os.getcwd()  #获取本py文件的当前路径
app = xw.App(visible=True, add_book=False)  #创建Excel应用,无工作簿
#打开当前路径上的数据文件,可写
wb=app.books.open(fullname=root+r"\整理食材数据.xlsx",read_only=False)
sht=wb.sheets(1)  #获取工作表
p=r"([一-龢]{1,}) (\d+\.?\d*元)"  #一个以上汉字后跟数字再跟元,有分组
arr=sht.range("A1";).value  #原始字符串
m=re.finditer(p,arr)  #查找匹配文本,可迭代对象形式返回
num=1  #记录行号
for i in m:  #遍历全部匹配文本
    num+=1  #行号加1
    sht.cells(num,2).value=i.group(1)  #写入分组1,食材名称
    sht.cells(num,3).value=i.group(2)  #写入分组2,采购金额

在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,提取食材名称和采购金额并写入第2列和第3列,如图8-4中处理后工作表所示。

应用示例3:数据汇总

图8-5中处理前工作表中第2列的数据为多次采购食材的记录,现要求计算每次采购的食材的总重量。

Document Image

图8-5 用零宽断言进行数据汇总

思路是使用零宽度正预测先行断言提取出重量单位前面的数字进行累加。

【Excel VBA】

示例文件的存放路径为Samples\ch20\Excel VBA\数据汇总.xlsm。

code.vba
Sub 正则29()
   Dim objReg As New RegExp  '输出正则对象
   Dim mcT As MatchCollection  '存放所有匹配结果
   Dim matT As Match  '存放单个匹配结果
   Dim dblSum As Double  '存放累加和
   With objReg
     .Global = True  '全局查找
     '正则表达式,零宽断言+分支条件
     .Pattern = "\d+\.?\d*(?=(公斤|千克|kg))"
     '遍历B2-B4单元格区域中的每条数据
     For Each c In Range("B2", Cells(Rows.Count, "B").End(xlUp))
       Set mcT = .Execute(c)  '执行查找
       dblSum = 0  '累加和初始化为0
       For Each matT In mcT  '遍历每个匹配结果
          dblSum = dblSum + matT  '累加求和
       Next
       c.Offset(0, 1) = dblSum  '将累加和写入工作表
     Next
  End With
End Sub

运行过程,输出处理结果如图8-5中处理后工作表所示。

【Python】

本示例数据文件的存放路径为Samples\ch20\Python\数据汇总.xlsx。本示例的py文件的存放路径为Samples\ch20\Python\数据汇总..py。

code.python
import xlwings as xw  #导入xlwings包
import os  #导入os包
import re  #导入re包
root = os.getcwd()  #获取本py文件的当前路径
app = xw.App(visible=True, add_book=False)  #创建Excel应用,无工作簿
#打开当前路径上的数据文件,可写
wb=app.books.open(fullname=root+r"\数据汇总.xlsx",read_only=False)
sht=wb.sheets(1)  #获取工作表
p=r"\d+\.?\d*(?=(公斤|千克|kg))"  #匹配单位前的数字
#获取B2-B4单元格区域中的数据
arr=sht.range("B2", sht.cells(sht.cells(1,"B").end("down").row, "B")).value
for i in range(len(arr)):  #遍历每条数据
    sm=0  #记录累加重量
    m=re.finditer(p,arr[i])  #找到所有匹配数据
    for j in m:  #遍历匹配数据
       sm+=int(j.group(0))  #求它们的和,就是总重量
    sht.cells(i+2,3).value=sm  #输出总重量

在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,计算各次采购食材的总重量并写入第3列,如图8-5中处理后工作表所示。[大谦Excel,dqexcel点com]