Найти и заменить текст в двойных кавычках на VBA - PullRequest
0 голосов
/ 11 февраля 2019

Я ищу способ найти и заменить в VBA, который просматривает текст только в двойных кавычках и обрабатывает все вхождения.

Я пишу парсер SQL, который преобразует операторы SQL Access Jet в T-SQL для SQL Server.Одна из моих неприятностей заключается в преобразовании двойных кавычек в одинарные, когда одинарные кавычки являются частью буквального вывода.

Я использовал SQL = Replace(SQL, """", "'"), пока не наткнулся на некоторые допустимые одинарные кавычки, встроенные в строки, которые будут испорчены этой командой.

Например, если оператор SQL в AccessSELECT "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 голосов
/ 11 февраля 2019

Вот решение на основе 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 & ''''
0 голосов
/ 11 февраля 2019

Пожалуйста, попробуйте этот подход.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...