我在寻找一种方式来查找和VBA,只有着眼于双引号内的文字,并处理所有出现替换。
我写一个SQL分析器将访问喷气SQL语句转换成T-SQL的SQL Server。其中存在挂起我正在将双引号为单引号时,单引号文本输出的一部分。
我一直在使用SQL = Replace(SQL, """", "'")
,直到我碰到嵌入到字符串的一些合法的单引号,这将是该命令搞的一团糟来了。
例如,如果在Access中的SQL语句是SELECT "Kat's code is righteous"
替换()函数最终将转换这SELECT 'Kat's code is righteous'
这导致在T-SQL不会喜欢一个额外的单引号。
我正在寻找将返回SELECT 'Kat''s code is righteous'
所以它会在T-SQL工作的功能。
我开始寻找一个正则表达式的解决方案,然后决定它可能是太复杂了,所以我开始写通过字符串中的每个字符循环的功能。一个挑战是,最终我将使用VBA替换()函数,并没有报告有多少次作出了更换,所以之后的更换,我不知道有多少移动循环索引来搜索下一场比赛。现在我靠在椅背上正则表达式,但我不知道在VBA中如何把它每一个匹配结果中替换文本,并尽量减少其破坏字符串的机会。我试过"([^"]*)"
的正则表达式,但不知道如何使它只查找包含单引号匹配。例如: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 & ''''
喷气SQL的细微差别是,它允许文字串被包裹在单引号或双引号,如In ('ab',"cd", 'efg')
。 T-SQL只接受单引号的字符串。
请尝试这种方法。
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
这是基于正则表达式的解决方案:
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 & ''''