特定的VBA / VBScript正则表达式相关问题(MS Access)

时间:2018-03-07 20:33:08

标签: regex vba debugging vbscript

更新时间:2018年3月12日中部标准时间下午1:44

创建一个名为http://vbfiddle.net的网站,在浏览器中实现并测试@ ctwheel的VBScript解决方案(MS IE 10+,安全性设置为“中”),该网站上的说明如何为您设置如果你想要玩 - 从jsfiddle.net的这个链接获取代码复制和粘贴到vbfiddle.net:https://jsfiddle.net/hcwjhmg9/ [ vbfiddle.net目前没有“保存”功能]),我发现@ ctwheel的VBScript RegEx运行成功,即使对于我给出的第3个示例行,但是当@ ctwheel的VBScript RegEx用于VBS for VAP for Microsoft Access 2016时,对于从数据库读取的记录“相同的“值,第三个子组只返回”Ray“,对于我给出的第三个示例行,它应该返回”Ray,CFP“,就像它在vbfiddle.net中一样。

我终于想到迭代数据库返回的字符串值的每个字符(在Microsoft Access中的VBA中),并将它与我直接输入的视觉等效字符串值的每个字符的迭代进行比较。代码(在Microsoft Access中的VBA中)。我得到以下结果:

First Name and Last Name: "G.L. (Pete) Ray, CFP"
--- 1st Text chars: "71 46 76 46 32 40 80 101 116 101 41 32 82 97 121 44" 
(Read value from database, appears same as below when Debug.Print is called on it)
--- 2nd Text chars: "71 46 76 46 32 40 80 101 116 101 41 32 82 97 121 44 32 67 70 80" (Typed by keyboard into a string within the code)
'G.L. (Pete) Ray,'
    strProperName>objSubMatch: "G.L."
    strProperName>objSubMatch: "Pete"
    strProperName>objSubMatch: "Ray,"
 Matching record(s): 3 of 1132 record(s).

我正在运行的RegEx正在针对“1st Text Chars”示例运行,并返回“Ray”,用于先前给定的第3个示例行的第3个子组:“G.L. (Pete) Ray, CFP”。但是,如果我对第二个类型的RegEx运行 - 直接输入代码 - “2nd Text chars”示例,第三个子组将按照预期在VBA for Microsoft Access 2016中返回“Ray,CFP”。

我现在正在使用@ctwheels提供的RegEx:

^([^(]+?)\s*\(\s*([^)]*?)\s*\)\s*(.*)

有人可以解释这里发生了什么吗? 1)为什么从数据库返回的字符与使用键盘输入字符串返回的字符不同,通过直观地读取和复制它? 2)当如何直接从数据库中读取值时,如何使“1st Text Chars”字符/字符串序列的RegEx返回正确的第3个子组:“Ray, CFP”?

原始问题(上面更新的问题):

我在使用带有Regex引擎的Microsoft Access 2016的VBA中遇到问题我相信5.5 for VBScript。

这是我正在使用的正则表达式:

"(.*)\((.*)(\))(.*)"

我正在尝试解析字符串(分别在每个新行上):

Lawrence N. (Larry) Solomon
James ( Jim ) Alleman
G.L. (Pete) Ray, CFP

分为:

"Lawrence N.", "Larry", ")", "Solomon"
"James", "Jim", ")", "Alleman"
"G.L.", "Pete", ")", "Ray, CFP"

或者(最好)进入:

"Lawrence N.", "Larry", "Solomon"
"James", "Jim", "Alleman"
"G.L.", "Pete", "Ray, CFP"

其中引号中的部分(以逗号分隔)是子匹配中返回的部分(不含引号)

我使用以下代码:

           ' For Proper Name (strProperName):
            With objRegex
                .Global = False
                .MultiLine = False
                .IgnoreCase = True
                .Pattern = "(.*)\((.*)(\))(.*)"

                    '([\s|\S]*) work around to match every character?

                        '".*\(([^\s]*)[\s]*\(" '_
                        ''& "[\"
                        '[\(][\s]*([.|^\w]*)[\s]*\)"
                    ' "[\s]*(.*)[\s]*\("
                        ' does same as below except matches any or no whitespace preceding any characters,
                        ' and returns the following characters up to an opening parenthesis ("(") but excluding it,
                        ' as the first subgroup
                    ' "(.*)[\s]*\("
                        ' does same as below except matches any whitespace or no whitespace at all followed by an opening parenthesis ("(")
                        ' and returns the preceding characters as the first subgroup
                    ' "(.*)\("
                        ' matches all characters in a row that end with an open parenthesis, and returns all of these characters in a row
                        ' excluding the following open parenthesis as the first subgroup
                    ' "(.*?\(\s)"
                    ' "[^\(]*"
                        ' this pattern returns every character that isn't an opening parenthesis ("("), and when
                        ' it matches an open parenthesis, it does not return it or any characters after it
                    ' "[\(\s](.*)\)"
                        ' this pattern extracts everything between parenthesis in a line as its first submatch
                    ' "(?<=\().*"
                    ' "[^[^\(]*][.*]"
                    ' "(\(.*?\))"
                    ' "(\(.*?\))*([^\(].*[^\)])"
            End With

            If objRegex.Test(strFirstNameTrimmed) Then
                'Set strsMatches = objRegex.Execute(rs.Fields("First Name"))
                Set strsMatches = objRegex.Execute(strFirstNameTrimmed)



                Debug.Print "2:'" & strsMatches(0).Value & "'"

                If strsMatches(0).SubMatches.Count > 0 Then

                    For Each objSubMatch In strsMatches(0).SubMatches

                        Debug.Print "    strProperName>objSubMatch: """ & objSubMatch & """" 'Result: 000, 643, 888"

                        strProperName = objSubMatch

                    Next objSubMatch

                End If
            Else
                strProperName = "*Not Matched*"
            End If

在调试窗口/“立即窗口”中生成以下输出,因为它在VBA中已知,由(Ctrl + G)调出:

------------------------
First Name and Last Name: "Lawrence N. (Larry) Solomon"
2:'Lawrence N. (Larry)'
    strProperName>objSubMatch: "Lawrence N. "
    strProperName>objSubMatch: "Larry"
    strProperName>objSubMatch: ")"
    strProperName>objSubMatch: ""
Extracted Nick Name: "Larry"
Extracted Proper Name: ""
First Name and Last Name: "James ( Jim ) Alleman"
2:'James ( Jim )'
    strProperName>objSubMatch: "James "
    strProperName>objSubMatch: " Jim "
    strProperName>objSubMatch: ")"
    strProperName>objSubMatch: ""
Extracted Nick Name: "Jim"
Extracted Proper Name: ""
First Name and Last Name: "G.L. (Pete) Ray, CFP"
2:'G.L. (Pete) Ray,'
    strProperName>objSubMatch: "G.L. "
    strProperName>objSubMatch: "Pete"
    strProperName>objSubMatch: ")"
    strProperName>objSubMatch: " Ray,"
Extracted Nick Name: "Pete"
Extracted Proper Name: " Ray,"
Matching record(s): 3 of 1132 record(s).

3 个答案:

答案 0 :(得分:1)

See regex in use here

^
  • ([^(]+?)在行首处断言位置
  • (\s*\(之外的任何字符捕获一次或多次,但尽可能少捕获到捕获组1
  • (匹配任意数量的空白字符
  • \s*按字面意思匹配([^)]*?)
  • )匹配任意数量的空白字符
  • \s*\((之外的任何字符捕获一次或多次,但尽可能少捕获到捕获组2
  • \s*匹配任意数量的空白字符
  • (.*)按字面意思匹配["Lawrence N.", "Larry", "Solomon"] ["James", "Jim", "Alleman"] ["G.L.", "Pete", "Ray, CFP"]
  • fn2匹配任意数量的空白字符
  • def _fn2(): do_something_else() @transaction(True) def fn1(x=False): if x: return _fn2() do_something() fn2 = transaction(True)(_fn2) 将其余部分捕获到捕获组3

结果:

{{1}}

答案 1 :(得分:1)

你应该能够避免使用正则表达式,如果这是你的事情。

我对昵称包含在“()”中的测试数据做了一些假设。除此之外,代码应该是直截了当的,我希望。如果没有,请随意提问。还包含一个名为Test的测试例程。

Public Function ParseString(InputString As String) As String
    On Error GoTo ErrorHandler:

    Dim OutputArray   As Variant
    Const DoubleQuote As String = """"

    'Quick exit, if () aren't found, then just return original text
    If InStr(1, InputString, "(") = 0 Or InStr(1, InputString, ")") = 0 Then
        ParseString = InputString
        Exit Function
    End If

    'Replace the ) with (, then do a split
    OutputArray = Split(Replace(InputString, ")", "("), "(")

    'Check the array bounds and output accordingly
    'If there can only ever be 3 (0 - 2) elements, then you can change this if statement
    If UBound(OutputArray) = 2 Then
        ParseString = DoubleQuote & Trim$(OutputArray(0)) & DoubleQuote & ", " & _
                      DoubleQuote & Trim$(OutputArray(1)) & DoubleQuote & ", " & _
                      DoubleQuote & Trim$(OutputArray(2)) & DoubleQuote
    ElseIf UBound(OutputArray) = 1 Then
        ParseString = DoubleQuote & Trim$(OutputArray(0)) & DoubleQuote & ", " & _
                      DoubleQuote & Trim$(OutputArray(1)) & DoubleQuote
    Else
        ParseString = DoubleQuote & Trim$(OutputArray(LBound(OutputArray))) & DoubleQuote
    End If

CleanExit:
    Exit Function

ErrorHandler:
    ParseString = InputString
    Resume CleanExit
End Function

Sub Test()
    Dim Arr() As Variant: Arr = Array("Lawrence N. (Larry) Solomon", "James ( Jim ) Alleman", "G.L. (Pete) Ray, CFP")

    For i = LBound(Arr) To UBound(Arr)
        Debug.Print ParseString(CStr(Arr(i)))
    Next
End Sub

<强>结果

"Lawrence N.", "Larry", "Solomon"
"James", "Jim", "Alleman"
"G.L.", "Pete", "Ray, CFP"

答案 2 :(得分:0)

正则表达式\s*[()]\s*

详细说明:

  • [()]匹配任何空白字符零和无限次
  • (匹配列表中的单个字符)Dim str As String str = "Lawrence N. (Larry) Solomon" Set re = CreateObject("VBScript.RegExp") re.Global = True re.Pattern = "\s*[()]\s*" re.MultiLine = True Dim arr As Variant arr = Strings.Split(re.Replace(str, vbNullChar), vbNullChar) For Each Match In arr Debug.Print (Match) Next

VBA代码

Lawrence N.
Larry
Solomon

输出:

# configuration.py

...

def __init__(self):
  """Constructor"""
  # Default Base url
  self.host = "http://petstore.swagger.io:80/v2"