从最后一个和成对括号之间的字符串中提取文本

时间:2018-01-08 01:03:19

标签: vba ms-word word-vba

我试图从字符串中提取括号括起来的最后一个组。 字符串可以是以下变体之一:

String                             ' Extracted sub
--------------                     ' -------------
Some (text)                        ' text
Some text                          ' "" or "Some text"
Some (text) (here)                 ' here
Some (text) (is situated (here))   ' is situated (here)
Some text (is situated (here))     ' is situated (here)
Some (text) (is (situated (here))) ' is (situated (here))

我需要最后一个右括号和相应的左括号之间的substring

我测试了SplitMidInStrInStrRev的所有变种......

3 个答案:

答案 0 :(得分:2)

不确定你尝试了什么,但这个想法是(希望它的写作逻辑性):

  1. 找到最后(最右侧))
  2. 的位置
  3. 找到最右侧(
  4. 的位置
  5. 计算从#2到#1
  6. 的子字符串中有多少)
  7. 查看#2之前的字符,满足)时增加#3,满足(时减少#3,#3变为零时停止。
  8. 所需的输出是来自(#4 + 1)的子串(#1-1-#4)字符
  9. 如果找到不匹配的对,则会返回"ERROR: UNMATCHED BRACKETS!"

  10. 以下代码在Excel中测试(在评论中更新样本YowE3K)

    Option Explicit
    
    Function LastOutmostBracketText(ByVal InputText As String) As String
        Dim lRightMostCloseBracket As Long, CloseBracketCount As Long
        Dim lRightMostOpenBracket As Long
        Dim sTmp As String
    
        Dim sOutput As String
        If InStr(1, InputText, "(", vbTextCompare) > 0 And InStr(1, InputText, ")", vbTextCompare) > 0 Then
            ' Find the Last Close Bracket
            lRightMostCloseBracket = InStrRev(InputText, ")")
            ' Find the Last Open Bracket
            lRightMostOpenBracket = InStrRev(InputText, "(")
            If (lRightMostCloseBracket - lRightMostOpenBracket) > 1 Then
                ' Count how many Close brackets within the last Open and last Close bracket
                sTmp = Mid(InputText, lRightMostOpenBracket, lRightMostCloseBracket - lRightMostOpenBracket)
                CloseBracketCount = Len(sTmp) - Len(Replace(sTmp, ")", ""))
                ' Find the matching Open Bracket by looking at previous characters
                Do Until CloseBracketCount = 0 Or lRightMostOpenBracket = 1
                    If lRightMostOpenBracket > 0 Then lRightMostOpenBracket = lRightMostOpenBracket - 1
                    sTmp = Mid(InputText, lRightMostOpenBracket, 1)
                    Select Case sTmp
                        Case "(":   CloseBracketCount = CloseBracketCount - 1
                        Case ")":   CloseBracketCount = CloseBracketCount + 1
                    End Select
                Loop
                If lRightMostOpenBracket = 1 And CloseBracketCount > 0 Then
                    sOutput = "ERROR: UNMATCHED BRACKETS!" & vbCrLf & InputText
                Else
                    sOutput = Mid(InputText, lRightMostOpenBracket + 1, lRightMostCloseBracket - 1 - lRightMostOpenBracket)
                End If
            End If
        End If
        LastOutmostBracketText = sOutput
    End Function
    

答案 1 :(得分:1)

我怀疑正则表达式确实可以做得更好但这是我知道如何编写的代码(现在包含了@YowE3K的“错误案例”和他更清醒 - 尽管他自称疲倦 - 理解括号内的括号应该是什么处理的): -

Private Function LastBracket(ByVal Txt As String) As String
    ' 08 Jan 2018

    Dim Fun As String
    Dim x As Integer, y As Integer
    Dim n As Integer, m As Integer

    For n = 0 To Len(Txt) - 1
        Fun = Fun & Mid(Txt, Len(Txt) - n, 1)
    Next n

    n = InStr(Fun, ")")                         ' remove trailing text
    If n Then
        Fun = Mid(Fun, n)
    Else
        Exit Function                           ' no bracket found
    End If

    Do
        n = InStr(m + 1, Fun, "(")
        If n Then
            Txt = Left(Fun, n)
            m = n
            x = Len(Txt) - Len(Replace(Txt, "(", ""))
            y = Len(Txt) - Len(Replace(Txt, ")", ""))
        Else
            Exit Function                       ' paired bracket not found
        End If
    Loop Until x = y

    Fun = Txt
    Txt = ""
    For n = 1 To Len(Fun) - 2
        Txt = Txt & Mid(Fun, Len(Fun) - n, 1)
    Next n

    LastBracket = Txt
End Function

如果没有括号内的文本或括号为空,它将返回一个空字符串。以下是我跑的测试。

Private Sub TestUnpack()
    Debug.Print "Result = "; LastBracket("Some; Text")
    Debug.Print "Result = "; LastBracket("Some; Text()")
    Debug.Print "Result = "; LastBracket("Some(Text)")
    Debug.Print "Result = "; LastBracket("Some(Text)(here)")
    Debug.Print "Result = "; LastBracket("Some (text) (might be (here))")
    Debug.Print "Result = "; LastBracket("Some (text) (might be (situated (here)))")
    Debug.Print "Result = "; LastBracket("Some (text) (might be (situated (here))) not here")
    Debug.Print "Result = "; LastBracket("abc ((def) ghi (jkl) (mno (pqr)) stu) vwx")
End Sub

答案 2 :(得分:0)

使用CSet的方法略有不同(但大致相同):

Sub test()
    Dim i As Integer
    Dim str As String
    Dim rng As Range
    Dim l As Integer
    For i = 1 To ActiveDocument.Sentences.Count
        Set rng = ActiveDocument.Paragraphs.Item(i).Range
        rng.End = rng.End - 1
        l = Len(rng.Text)
        rng.Collapse wdCollapseEnd
        Do
            rng.MoveStartUntil cset:="(", Count:=-l
            rng.Start = rng.Start - 1
            str = rng.Text
        Loop While Len(Replace(str, "(", vbNullString)) <> Len(Replace(str, ")", vbNullString))
        Debug.Print str
        str = vbNullString
    Next i
End Sub

哦,我太懒了去除外括号,但我希望这不应该太有问题; - )