首页 > 解决方案 > 我需要一个正则表达式,它将返回字符串的空格分隔内容

问题描述

我需要一个适用于 VBA 的正则表达式,它将从字符串中检索数据组。

我想我有一些必需的正则表达式但是可能有更好更有效的方法?

字符串是:

("xs:/49.dwp" 149 (nil "sdfsfda" "16-12-10") ("V" "5" "R" "1" ",A,B,C,D,E,F,G,H,J") (nil "gt:\\lib\\iec2;gt://Libs/iec3/;gt://Libs/hyd/;gt://Libs/pid/;") ("xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht" "xs:\\a-04.sht") ((1 "01A" "" "xs:\\a-01.sht" "dgddgdfgd" "" "" "" "") (2 "" "" "xs:\\a-01A.sht""ergfdgdfgdtger44" "" "" "" "") (3 "" "" "xs:\\a-02.sht" "34vbb" "" "" "" "")) ("xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht""xs:\\a-04.sht" "xs:\\a-09.sht" "xs:\\a-10.sht" "xs:\\a-11.sht" "xs:\\a-12.sht") nil ("xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht""xs:\\a-04.sht" "xs:\\a-09.sht" "xs:\\a-10.sht" "xs:\\a-11.sht" "xs:\\a-12.sht") (("" "xs:\\a-01.sht") ("" "xs:\\a-01A.sht") ("" "xs:\\a-02.sht") ("" "xs:\\a-03.sht") ("" "xs:\\a-11.sht") ("" "xs:\\a-12.sht")))

在这个字符串中,我需要获取 11 个单独的组。每个组由一个空格分隔。

有些组只包含用引号括起来的文本,有些是数字,有些是一系列用引号括起来的文本。所有 11 组也都被一对括号包围。

我将描述这 11 个组以及我目前拥有的内容:

第 1 组 - "xs:/49.dwp"。我有^\("(.+)" \d+哪个回报xs:/49.dwp

第 2 组 - 149。我有" (\d{3}) \(哪个回报149

到目前为止,一切都很好!!

第 3 组 -(nil "sdfsfda" "16-12-10")

第 4 组 -("V" "5" "R" "1" ",A,B,C,D,E,F,G,H,J")

第 5 组 -(nil "gt:\\lib\\iec2;gt://Libs/iec3/;gt://Libs/hyd/;gt://Libs/pid/;")

第 6 组 -("xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht" "xs:\\a-04.sht")

第 7 组 -((1 "01A" "" "xs:\\a-01.sht" "dgddgdfgd" "" "" "" "") (2 "" "" "xs:\\a-01A.sht""ergfdgdfgdtger44" "" "" "" "") (3 "" "" "xs:\\a-02.sht" "34vbb" "" "" "" ""))

第 8 组 -("xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht""xs:\\a-04.sht" "xs:\\a-09.sht" "xs:\\a-10.sht" "xs:\\a-11.sht" "xs:\\a-12.sht")

第 9 组 -nil

第 10 组 -("xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht""xs:\\a-04.sht" "xs:\\a-09.sht" "xs:\\a-10.sht" "xs:\\a-11.sht" "xs:\\a-12.sht")

第 11 组 -(("" "xs:\\a-01.sht") ("" "xs:\\a-01A.sht") ("" "xs:\\a-02.sht") ("" "xs:\\a-03.sht") ("" "xs:\\a-11.sht") ("" "xs:\\a-12.sht"))

在第 3 组和第 11 组之间,我试图获得一个匹配左括号和右括号之间所有内容的模式,以便获得所有组,但这里有几个问题。

1) 有括号括起来的组,例如第 7 组和第 11 组。

2) 第 9 组在这些括号组中间,没有被括号包围。

我需要一个正则表达式来捕获 11 个组。我不需要外围组括号,但我显然需要内部组的括号。

标签: regexvba

解决方案


免责声明:我冒着在这里引发一场激烈战争的风险,因为我不是正则表达式的忠实粉丝。现在你知道我的偏见了,但我仍然认为我对这个特定问题有一点看法。如果您想更深入地讨论正则表达式,您可以阅读这篇文章这个答案以获得一些好处。

尝试为您的输入字符串提出一个正则表达式将是有问题的,原因如下:

  1. 您对组分隔符的定义不一致,难以实施。例如,您的第一组以括号开头,"("但以空格结尾" "。第二组以空格开头和结尾。您的第三组以括号开头和结尾,但包含空格。你最终可能会写出一个成功的正则表达式,但理解它会让我头疼。
  2. 您的示例输入只是 - 一个示例。对于您在 regexp 语句中定义的任何规则,其他输入行将有自己的“例外”。反过来,这将导致您修改您的正则表达式并使其更加迟钝(并可能违反您以前的规则)。

我的建议是使用一些定义明确的规则来解析输入,这些规则既易于对您的输入实施,又易于在您的逻辑中实现。为了支持我的建议,我稍微修改了我个人库中的一些令牌解析代码。此函数的想法是重复解析单个字符串并提取由定义的开始和停止字符包围的所有“令牌”子字符串。

Private Function GetNextToken(ByRef startAt As Long, _
                              ByVal str As String, _
                              Optional ByVal startCharacter As String = "(", _
                              Optional ByVal stopCharacter As String = ")") As String
    Dim thisToken As String
    Dim thisChar As String
    Dim i As Long
    For i = startAt To Len(str)
        thisChar = Mid$(str, i, 1)
        Select Case thisChar
            Case startCharacter, stopCharacter
                Exit For
            Case Else
                thisToken = thisToken & thisChar
        End Select
    Next i
    startAt = i + 1
    GetNextToken = Trim$(thisToken)
End Function

请注意,参数startAt已传递ByRef。这意味着它的值将被函数修改并传回给调用者。该函数将有效地“遍历”解析字符串的起点。所以它会扫描输入字符串,直到它碰到一个开始或停止字符,(可能)沿途建立一个字符串。空字符串被Trim添加到空字符串。

要使用该功能,我将您的示例输入放在单元格 A1 中并使用以下测试程序:

Option Explicit

Sub ParseMe()
    Dim source As String
    source = Range("A1").Value

    Dim token As String
    Dim tokens As Collection
    Set tokens = New Collection

    Dim startAt As Long
    'source = "(abcd(efg(hijklm)))"
    startAt = 1
    Do While startAt < Len(source)
        token = GetNextToken(startAt, source)
        'Debug.Print "token is '" & token & "', next start at " & startAt
        If Not token = vbNullString Then
            tokens.Add token
        End If
    Loop

    Dim thisToken As Variant
    Debug.Print "there are " & tokens.Count & " tokens:"
    For Each thisToken In tokens
        Debug.Print "   " & thisToken
    Next thisToken
End Sub

这给出了输出(使用您的示例输入):

there are 17 tokens:
   "xs:/49.dwp" 149
   nil "sdfsfda" "16-12-10"
   "V" "5" "R" "1" ",A,B,C,D,E,F,G,H,J"
   nil "gt:\\lib\\iec2;gt://Libs/iec3/;gt://Libs/hyd/;gt://Libs/pid/;"
   "xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht" "xs:\\a-04.sht"
   1 "01A" "" "xs:\\a-01.sht" "dgddgdfgd" "" "" "" ""
   2 "" "" "xs:\\a-01A.sht""ergfdgdfgdtger44" "" "" "" ""
   3 "" "" "xs:\\a-02.sht" "34vbb" "" "" "" ""
   "xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht""xs:\\a-04.sht" "xs:\\a-09.sht" "xs:\\a-10.sht" "xs:\\a-11.sht" "xs:\\a-12.sht"
   nil
   "xs:\\a-01.sht" "xs:\\a-01A.sht" "xs:\\a-02.sht" "xs:\\a-03.sht""xs:\\a-04.sht" "xs:\\a-09.sht" "xs:\\a-10.sht" "xs:\\a-11.sht" "xs:\\a-12.sht"
   "" "xs:\\a-01.sht"
   "" "xs:\\a-01A.sht"
   "" "xs:\\a-02.sht"
   "" "xs:\\a-03.sht"
   "" "xs:\\a-11.sht"
   "" "xs:\\a-12.sht"

在此之后,由您和您的业务逻辑决定是否"xs:/49.dwp" 149应该使用空格分隔符来分解单个令牌(第一个:)。如果是这样,您可以使用以下Split功能:

Split(token, " ")

推荐阅读