如何在字符串中找到引用的文本?

How can I find quoted text in a string?

例子

假设我有一个字符串:

"I say ""Hello world"" and she says ""Excuse me?"""

VBA 会将此字符串解释为:

I say "Hello world" and she says "Excuse me?"

一个更复杂的例子:

我有一个字符串:

"I say ""Did you know that she said """"Hi there!"""""""

VBA 将此字符串解释为:

I say "Did you know that she said ""Hi there!"""

如果我们删除“我说”

"Did you know that she said ""Hi there!"""

我们可以继续解析vba中的字符串:

Did you know that she said "Hi there!"

问题

最终我想要一些函数,sBasicQuote(quotedStringHierarchy as string),其中 returns 一个包含字符串层次结构中上一级的字符串。

例如

dim s as string
s = "I say ""Did you know that she said """"Hi there!"""""""
s = sBasicQuote(s) ' returns 'I say "Did you know that she said ""Hi there!"""'
s = sBasicQuote(s) ' returns 'Did you know that she said "Hi there!"'
s = sBasicQuote(s) ' returns 'Hi there!'

我只是想不出适用于此的算法...您几乎需要替换所有双引号,但是当您替换了第 n 个双引号后,您必须跳到第 n+1 个双引号?

如何在 VBA 中实现这一点?

我的解决方案

我花了更多时间思考并想出了这个解决方案。

Function sMineDoubleQuoteHierarchy(s As String) As String
    'Check the number of quotes in the string are even - sanity check
    If (Len(s) - Len(Replace(s, """", ""))) Mod 2 <> 0 Then sMineDoubleQuoteHierarchy = "Error - Odd number of quotes found in sMineDoubleQuoteHierarchy() function": Exit Function

    'First thing to do is find the first and last *single* quote in the string
    Dim lStart, lEnd, i As Long, fs As String
    lStart = InStr(1, s, """")
    lEnd = InStrRev(s, """")

    'After these have been found we need to remove them.
    s = Mid(s, lStart + 1, lEnd - lStart - 1)

    'Start at the first character
    i = 1

    Do While True
        'Find where the next double quote is
        i = InStr(1, s, """""")

        'if no double quote is found then concatenate with fs with the remainder of s
        If i = 0 Then Exit Do

        'Else add on the string up to the char before the ith quote
        fs = fs & Left(s, i - 1)

        'Replace the ith double quote with a single quote
        s = Left(s, i - 1) & Replace(s, """""", """", i, 1)

        'Increment by 1 (ensuring the recently converted double quote is no longer a single quote
        i = i + 1
    Loop

    'Return fs
    sMineDoubleQuoteHierarchy = s
End Function

这个解决方案发生了什么?

该过程的第一部分是从字符串中删除第一个和最后一个单引号并返回它们之间的文本。然后我们循环遍历替换 "" 的每个实例并将其替换为 " 的字符串。每次我们这样做时,我们都会跳到下一个字符,以确保像 """" 这样的字符串会转到 "" 而不是 ".

还有其他人有 better/more 紧凑的解决方案吗?


编辑

在这个论坛中的所有建议之后,我解决了这个问题。它有一些额外的错误陷阱来查找验证嵌套字符串。

Public Function DoubleQuoteExtract(ByVal s As String, Optional ByRef ErrorLevel As Boolean) As String
    'This effectively parses the string like BASIC does by removing incidents of "" and replacing them with "

    'SANITY CHECK - Check even number of quotes
    Dim countQuote As Double
    countQuote = Len(s) - Len(Replace(s, """", ""))

    'Calculate whether or not quote hierarchy is correct:
    '"..."          - Is okay           - Count Quotes = 2      - Count Quotes / 2 = 1
    '""...""        - Is not okay       - Count Quotes = 4      - Count Quotes / 2 = 2
    '"""..."""      - Is okay           - Count Quotes = 6      - Count Quotes / 2 = 3
    '""""...""""    - Is not okay       - Count Quotes = 8      - Count Quotes / 2 = 4
    'etc.
    'Ultimately: IF CountQuotes/2 = Odd The string hierarchy is setup fine
    '            IF CountQuotes/2 = Even, The string Hierarchy is setup incorrectly.

    Dim X As Double: X = countQuote / 2
    Dim ceil As Long: ceil = Int(X) - (X - Int(X) > 0)
    If ceil Mod 2 <> 0 Then sDoubleQuoteExtract = "#Error - Incorrect number of double quotes forming an incomplete hierarchy.": GoTo ErrorOccurred

    'If an odd number of quotes are found then they cannot be paired correctly, thus throw error
    If countQuote Mod 2 <> 0 Then sDoubleQuoteExtract = "#Error - Odd number of quotes found in sMineDoubleQuoteHierarchy() function": GoTo ErrorOccurred


    'Find the next incident of single quote. Trim the string to this
    s = Mid(s, InStr(1, s, String(1, Chr(34))))

    'replace all instances of "" with "
    s = Replace(s, String(2, Chr(34)), String(1, Chr(34)))

    'Finally trim off the first and last quotes
    DoubleQuoteExtract = Mid(s, 2, Len(s) - 2)
    ErrorLevel = False
    Exit Function
ErrorOccurred:
    ErrorLevel = True
End Function

你可以这样做

Public Sub test()

Dim s As String
s = "I say ""Did you know that she said """"Hi there!"""""""

Debug.Print DoubleQuote(s, 0)
Debug.Print DoubleQuote(s, 1)
Debug.Print DoubleQuote(s, 2)

End Sub

Public Function DoubleQuote(strInput As String, intElement As Integer) As String

Dim a() As String

strInput = Replace(strInput, String(2, Chr(34)), String(1, Chr(34)))

a = Split(strInput, chr(34))

DoubleQuote = a(intElement)


End Function

另一个稍微修改的版本更准确一些

`Public Function DoubleQuote(strInput As String, intElement As Integer) As String

Dim a() As String
Dim b() As String
Dim i As Integer

ReDim b(0)

a = Split(strInput, Chr(34))
'   ***** See comments re using -1 *******
For i = 0 To UBound(a) - 1

    If Len(a(i)) = 0 Then
        b(UBound(b)) = Chr(34) & a(i + 1) & Chr(34)
        i = i + 1
    Else
        b(UBound(b)) = a(i)

    End If

    ReDim Preserve b(UBound(b) + 1)

Next i

DoubleQuote = b(intElement)

End Function`

我认为以下将 return 您在嵌套引用示例中寻找的内容。你的第一个例子并不是嵌套引号的情况。

Option Explicit
Sub NestedQuotes()
    Const s As String = "I say ""Did you know that she said """"Hi there!"""""""
    Dim COL As Collection
    Dim Start As Long, Length As Long, sTemp As String, V As Variant

Set COL = New Collection
sTemp = s
COL.Add sTemp
Do Until InStr(sTemp, Chr(34)) = 0
    sTemp = COL(COL.Count)
    sTemp = Replace(sTemp, String(2, Chr(34)), String(1, Chr(34)))
        Start = InStr(sTemp, Chr(34)) + 1
        Length = InStrRev(sTemp, Chr(34)) - Start
    sTemp = Mid(sTemp, Start, Length)
    COL.Add sTemp
Loop

For Each V In COL
    Debug.Print V
Next V

End Sub