【问题标题】:Find and Replace text that is within double quotes with VBA使用 VBA 查找和替换双引号内的文本
【发布时间】:2019-02-11 04:47:40
【问题描述】:

我正在寻找一种在 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 中如何让它替换每个匹配结果中的文本并最大限度地减少它破坏字符串的机会。我尝试了"([^"]*)" 的正则表达式模式,但不知道如何让它只找到包含单引号的匹配项。示例:https://regexr.com/483n9

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

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 只接受单引号中的字符串。

【问题讨论】:

  • 你不能只修剪现有的限定符,用"替换转义的"",用''转义',然后用单引号括起来重新限定它吗?
  • 我尝试了我认为您的建议,但它将right('source code',4) 转换为right(''source code'',4)。这是我提到的细微差别的副作用。
  • 在这种情况下,您可能希望同时从左右两侧“扫描”字符数组以找到外壳。一旦你有了这个,替换方法就可以在子字符串上工作,不是吗?
  • 您是否建议双引号内不能有两个单引号,即 "Kat's code is Aaron's code." 不可能发生,即您如何确定 'source code' 保持 'source code'?

标签: regex tsql ms-access vba


【解决方案1】:

请尝试这种方法。

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

【讨论】:

    【解决方案2】:

    这是基于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 & ''''
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-23
      • 1970-01-01
      • 2012-11-14
      • 1970-01-01
      • 2016-08-10
      • 2020-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多