regex - 我需要一个正则表达式,它将返回字符串的空格分隔内容
问题描述
我需要一个适用于 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 个组。我不需要外围组括号,但我显然需要内部组的括号。
解决方案
免责声明:我冒着在这里引发一场激烈战争的风险,因为我不是正则表达式的忠实粉丝。现在你知道我的偏见了,但我仍然认为我对这个特定问题有一点看法。如果您想更深入地讨论正则表达式,您可以阅读这篇文章和这个答案以获得一些好处。
尝试为您的输入字符串提出一个正则表达式将是有问题的,原因如下:
- 您对组分隔符的定义不一致,难以实施。例如,您的第一组以括号开头,
"("
但以空格结尾" "
。第二组以空格开头和结尾。您的第三组以括号开头和结尾,但包含空格。你最终可能会写出一个成功的正则表达式,但理解它会让我头疼。 - 您的示例输入只是 - 一个示例。对于您在 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, " ")
推荐阅读
- python - Pytest:如何盲目运行任何子进程并捕获所有输出?
- python - Pandas 将所有列除以其最大跳过第一列
- python - Django视图重定向('主页')
- python-3.x - 熊猫,情节热图和矩阵
- python - 尝试制作简单的自动售货机程序时的无限循环
- python - 使用 pandas 在同一行中计算上一年的销售额
- javascript - 数据表 - 从 Mysql 数据转换:使用 moment.js 将字符串转换为日期对象
- saleor - 登录期间销售或仪表板 CORS 错误(CORS 被阻止)
- linux - Ansible 挂载模块更新 fstab 未能在 EC2 实例中进行状态检查
- pandas - 在 Python 中将打印结果存储在数据框中