Access交流中心

北京 | 上海 | 天津 | 重庆 | 广州 | 深圳 | 珠海 | 汕头 | 佛山 | 中山 | 东莞 | 南京 | 苏州 | 无锡 | 常州 | 南通 | 扬州 | 徐州 | 杭州 | 温州 | 宁波 | 台州 | 福州 | 厦门 | 泉州 | 龙岩 | 合肥 | 芜湖 | 成都 | 遂宁 | 长沙 | 株洲 | 湘潭 | 武汉 | 南昌 | 济南 | 青岛 | 烟台 | 潍坊 | 淄博 | 济宁 | 太原 | 郑州 | 石家庄 | 保定 | 唐山 | 西安 | 大连 | 沈阳 | 长春 | 昆明 | 兰州 | 哈尔滨 | 佳木斯 | 南宁 | 桂林 | 海口 | 贵阳 | 西宁 | 乌鲁木齐 | 包头 |

[5分]请教一个比较复杂的正则表达式问题

煮江品茶  发表于:2013-01-26 20:12:48  
复制

我在写一个程序,为了简化输入需要写一个与正则表达式有关的函数,我希望输入一个字符串,这个字符串中包含形如:sum(v(1,1):v(3,3))的子字符串。
如何用一个自定义函数将这个子字符串替换为形如:
(v(1,1)+v(1,2)+v(1,3)+v(2,1)+v(2,2)+v(2,3)+v(3,1)+v(3,2)+v(3,3))
的子字符串,并返回替换后的字符串。由于对正则表达式不太熟悉,望帮忙写一个自定义函数。谢谢!!!

 

Top
殷小宝 发表于:2013-01-26 20:52:47

Funtion arraysum (A(a,b)&":"&A(c,d)) As String

Dim i,j As Integer

Dim B As Variant

For i=a To c

  For j=b To d

  arraysum=arraysum &" +"& B(i,j)

  Next

Next

End Fuction



殷小宝 发表于:2013-01-26 20:56:33

Funtion arraysum (A(a,b)&":"&A(c,d)) As String

Dim i,j As Integer

For i=a To c

  For j=b To d

  arraysum=arraysum &" +" & A(i,j)

  Next

Next

End Fuction



煮江品茶 发表于:2013-01-26 21:58:17

呵呵,没那么简单。

诸如:以下的字符串,都能被替换为加号连接的数组字符串。这是正则表达式问题,其他方法解不出来的。

“round(sum(v(1,2):v(2,4)/5,2)”

"iif(sum(v(2,2):v(4,4))=0,0,1/sum(v(2,2):v(4,4)))"



殷小宝 发表于:2013-01-27 10:24:35
我知道是没有这么简单,否则老师不会发贴了。

何保辛 发表于:2015-02-07 17:17:51

给你第一版吧,只是把文本表达式转换为 VBA表达式。
我认为最有效率的应该是把 数组传过去 马上运算,所以那个会是第二版。
不过这两版都是耗点资源的,regexp 已经是非常高效的文本处理器,但是如果你会做非常强大的“编译器”的话,一段文本的处理是错误的!
正确应该是一个一个字符读入,处理当前的“语法错误”,和使用堆栈来运算 “当前值”的。

Function ggg(str As String)

Dim re As RegExp, m As MatchCollection, sm As SubMatches, vs() As Variant, vsqty As Long

vsqty = 0
Set re = New RegExp
re.Global = True
re.IgnoreCase = True
re.Multiline = True

ReDim vs(vsqty)
re.Pattern = "(\w+)\(([\w\d]+)\((\d+),(\d+)\)\:([\w\d]+)\((\d+),(\d+)\)\)"

ggg = str
Set m = re.Execute(str)
Do While m.Count > 0
    Set sm = m(0).SubMatches
    vsqty = 0
    ReDim vs(0)
    vs(0) = "[SyntaxError]"
    If InStr("sum average", sm(0)) Then
        If sm(1) = sm(4) Then
    
            sti = IIf(sm(2) < sm(5), 1, -1)
            stj = IIf(sm(3) < sm(6), 1, -1)
            For i = sm(2) To sm(5) Step sti
                For j = sm(3) To sm(6) Step stj
                    ReDim Preserve vs(vsqty)
                    vs(vsqty) = sm(1) & "(" & i & "," & j & ")"
                    vsqty = vsqty + 1
                Next
            Next
            
        End If
        If sm(0) = "sum" Then
            rep = "(" & Join(vs, "+") & ")"
        ElseIf sm(0) = "average" Then
            rep = "(" & Join(vs, "+") & ")/" & vsqty
        End If
    End If
        
    ggg = Replace(ggg, m(0), rep, 1, 1)
        
    Set m = re.Execute(ggg)
    
Loop


End Function

第一版执行结果:
? ggg("round(sum(v(1,2):v(2,4))/5,2)+average(v(1,2):v(2,3))*3")

round((v(1,2)+v(1,3)+v(1,4)+v(2,2)+v(2,3)+v(2,4))/5,2)+(v(1,2)+v(1,3)+v(2,2)+v(2,3))/4*3

这个版本让你把表达式转换成为 VBA 表达式,自己eval 吧!


第二版,需要做再说吧!

第三版,单字节处理版,付费的可以帮你做个动态语法编译器出来的! 

给你第一版吧,只是把文本表达式转换为 VBA表达式。
我认为最有效率的应该是把 数组传过去 马上运算,所以那个会是第二版。
不过这两版都是耗点资源的,regexp 已经是非常高效的文本处理器,但是如果你会做非常强大的“编译器”的话,一段文本的处理是错误的!
正确应该是一个一个字符读入,处理当前的“语法错误”,和使用堆栈来运算 “当前值”的。

Function ggg(str As String)

Dim re As RegExp, m As MatchCollection, sm As SubMatches, vs() As Variant, vsqty As Long

vsqty = 0
Set re = New RegExp
re.Global = True
re.IgnoreCase = True
re.Multiline = True

ReDim vs(vsqty)
re.Pattern = "(\w+)\(([\w\d]+)\((\d+),(\d+)\)\:([\w\d]+)\((\d+),(\d+)\)\)"

ggg = str
Set m = re.Execute(str)
Do While m.Count > 0
    Set sm = m(0).SubMatches
    vsqty = 0
    ReDim vs(0)
    vs(0) = "[SyntaxError]"
    If InStr("sum average", sm(0)) Then
        If sm(1) = sm(4) Then
    
            sti = IIf(sm(2) < sm(5), 1, -1)
            stj = IIf(sm(3) < sm(6), 1, -1)
            For i = sm(2) To sm(5) Step sti
                For j = sm(3) To sm(6) Step stj
                    ReDim Preserve vs(vsqty)
                    vs(vsqty) = sm(1) & "(" & i & "," & j & ")"
                    vsqty = vsqty + 1
                Next
            Next
            
        End If
        If sm(0) = "sum" Then
            rep = "(" & Join(vs, "+") & ")"
        ElseIf sm(0) = "average" Then
            rep = "(" & Join(vs, "+") & ")/" & vsqty
        End If
    End If
        
    ggg = Replace(ggg, m(0), rep, 1, 1)
        
    Set m = re.Execute(ggg)
    
Loop


End Function

第一版执行结果:
? ggg("round(sum(v(1,2):v(2,4))/5,2)+average(v(1,2):v(2,3))*3")

round((v(1,2)+v(1,3)+v(1,4)+v(2,2)+v(2,3)+v(2,4))/5,2)+(v(1,2)+v(1,3)+v(2,2)+v(2,3))/4*3

这个版本让你把表达式转换成为 VBA 表达式,自己eval 吧!


第二版,需要做再说吧!

第三版,单字节处理版,付费的可以帮你做个动态语法编译器出来的! 



总记录:5篇  页次:1/1 9 1 :