使用VBA查找和替换双引号内的文本

时间:2019-02-11 04:47:40

标签: regex vba tsql ms-access access-vba

我正在寻找一种在VBA中查找和替换的方法,该方法仅查看双引号内的文本并处理所有出现的情况。

我正在编写一个SQL解析器,它将Access Jet SQL语句转换为SQL Server的T-SQL。我遇到的麻烦之一是当单引号是文字输出的一部分时,将双引号转换为单引号。

我一直使用SQL = Replace(SQL, """", "'")直到遇到嵌入在字符串中的合法单引号,这些引号会被该命令弄乱。

例如,如果Access中的SQL语句为SELECT "Kat's code is righteous"

Replace()函数最终会将其转换为SELECT 'Kat's code is righteous',这将导致T-SQL不希望使用额外的单引号。

我正在寻找一个将返回SELECT 'Kat''s code is righteous'的函数,以便它可以在T-SQL中使用。

我从寻找RegEx解决方案开始,然后认为它可能太复杂了,所以我开始编写一个遍历字符串中每个字符的函数。一个挑战是,最终我将要使用VBA Replace()函数,并且不会报告进行了多少次替换,因此在替换之后,我不确定要移动多少循环索引来搜索下一场比赛。现在,我依靠RegEx,但是不确定在VBA中如何使它替换每个匹配结果中的文本,并最大程度地减少损坏字符串的可能性。我尝试过使用"([^"]*)"的RegEx模式,但不确定如何使其仅查找包含单引号的匹配项。示例:https://regexr.com/483n9

我已将示例SQL select语句加载到变量中进行测试:

Public Sub Test_ReplaceInQuotes()

    Dim sTest As String

    sTest = "SELECT ""Kat's code is righteous."", left(""abc"",1), right('source code',4), ""Aaron's code has been righteous too."", ""Kat's code is righteous."", ""Right answer is '"" & Table.RightAnswer & ""'"""
    Debug.Print "Access:", sTest

    Debug.Print "Converted:", ReplaceInQuotes(sTest, "'", "''")
    'Debug.Print "Converted:", ReplaceInQuotes(sTest, "code", "source code") ' <- Make sure a longer replacement string doesn't break it.
    'Debug.Print "Converted:", ReplaceInQuotes(sTest, "right", "hid") ' <- Make sure it doesn't mess up the right() function.

    ' In another part of my parser I will replace ALL double quotes with single quotes, and & with +.
    Debug.Print "Final TSQL:", replace(ReplaceInQuotes(sTest, "'", "''"), """", "'")
End Sub

这是我希望它生成的输出:

Access:       SELECT "Kat's code is righteous.", left("abc",1), right('source code',4), "Aaron's code has been righteous too.", "Kat's code is righteous.", "Right answer is '" & Table.RightAnswer & "'"
Converted:    SELECT "Kat''s code is righteous.", left("abc",1), right('source code',4), "Aaron''s code has been righteous too.", "Kat''s code is righteous.", "Right answer is ''" & Table.RightAnswer & "''"
Final TSQL:   SELECT 'Kat''s code is righteous.', left('abc',1), right('source code',4), 'Aaron''s code has been righteous too.', 'Kat''s code is righteous.', 'Right answer is ''' & Table.RightAnswer & ''''

Jet SQL的一个细微之处在于它允许将文字字符串用单引号或双引号引起来,例如In ('ab',"cd", 'efg')。 T-SQL仅接受单引号中的字符串。

2 个答案:

答案 0 :(得分:0)

请尝试这种方法。

Public Sub Test_ReplaceInQuotes()

    Dim sTest As String
    Dim Sp() As String
    Dim p As Integer, q As Integer
    Dim i As Integer

    sTest = "SELECT ""Kat's code is righteous."", left(""abc"",1), right('source code',4), ""Aaron's code has been righteous too."", ""Kat's code is righteous."", ""Right answer is '"" & Table.RightAnswer & ""'"""
'    Debug.Print "Access:", sTest
    Sp = Split(sTest, ",")

    For i = 0 To UBound(Sp)
        p = InStr(Sp(i), "('")
        If p Then
            If Right(Trim(Sp(i)), 1) = "'" Then
                Sp(i) = Left(Sp(i), p) & Chr(34) & Mid(Sp(i), p + 2)
                For q = Len(Sp(i)) To 1 Step -1
                    If Mid(Sp(i), q, 1) = "'" Then
                        Sp(i) = Left(Sp(i), q - 1) & Chr(34) & Mid(Sp(i), q + 1)
                        Exit For
                    End If
                Next q
            End If
        End If
    Next i
    Debug.Print Replace(Replace(Join(Sp, ","), "'", "''"), Chr(34), "'")
End Sub

答案 1 :(得分:0)

这是基于RegEx的解决方案:

Option Explicit

Sub Test()

    Dim s As String
    Dim r As String
    Dim i As Long
    Dim m As Object

    s = "SELECT ""Kat's code is righteous."", left(""abc"",1), right('source code',4), ""Aaron's code has been righteous too."", ""Kat's code is righteous."", ""Right answer is '"" & Table.RightAnswer & ""'"""
    r = ""
    i = 1
    With CreateObject("VBScript.RegExp")
        .Global = True
        .Pattern = "('(?:''|[^'])*')|(""[^""]*"")"
        For Each m In .Execute(s)
            With m
                If .SubMatches(1) <> "" Then
                    r = r & Mid(s, i, .FirstIndex + 1 - i)
                    r = r & Replace(Replace(Mid(s, .FirstIndex + 1, .Length), "'", "''"), """", "'")
                Else
                    r = r & Mid(s, i, .FirstIndex + 1 + .Length - i)
                End If
                i = .FirstIndex + 1 + .Length
            End With
        Next
    End With
    If i <= Len(s) Then r = r & Mid(s, i, Len(s) - i + 1)
    Debug.Print s
    Debug.Print r

End Sub

输出如下:

SELECT "Kat's code is righteous.", left("abc",1), right('source code',4), "Aaron's code has been righteous too.", "Kat's code is righteous.", "Right answer is '" & Table.RightAnswer & "'"
SELECT 'Kat''s code is righteous.', left('abc',1), right('source code',4), 'Aaron''s code has been righteous too.', 'Kat''s code is righteous.', 'Right answer is ''' & Table.RightAnswer & ''''