我正在寻找一种在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仅接受单引号中的字符串。
答案 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 & ''''