Как сгенерировать строки Python с переменными форматирования, которые содержат апострофы и / или кавычки?

Я создал функцию для создания команд sqlite в python 3.6 из текста, который я собираю с веб-сайтов. Длина команды sql зависит от полученного текста.

def build_sql_stmnt(row, table, col_val):
    """builds an sql_stmnt to query fencers_db1.sqlite
       input: 
            row -- string, row data wanted
            table -- string, table to query
            col_val -- tuple with column/value pairs
                  Ex1: (('column', value),)
                  Ex2: (('column1', value1), ('column2', value2))
        returns: sql_stmnt -- string to be used as c.execute SELECT argument
    """    


    string = ''
    countdown = len(col_val)

    for pair in col_val: 
        if countdown > 1:
            string = string + ("""{} = '{}' AND """.format(pair[0], pair[1]))
        else:
            string = string + ("""{} = '{}'""".format(pair[0], pair[1]))

        countdown -= 1

    sql_stmnt = """SELECT {rw} FROM {tbl} WHERE {s};""".format(
                rw = row,
                tbl = table,
                s = string)
     return sql_stmnt

Я прибег к тройным кавычкам для определения строк выше, когда обнаружил, что очищаемый мной текст может включать двойные кавычки ("). Теперь я обнаружил, что текст, который я очищаю, также может включать апострофы ('). Когда я запускаю функцию когда col_val включает апостроф («Клуб фехтовальщиков»), я получаю следующую ошибку:

OperationalError: near "Club": syntax error

Следующее возвращает ту же ошибку:

 if countdown > 1:
        string = string + ("""{} = \'{}\' AND """.format(p0, p1))
    else:
        string = string + ("""{} = \'{}\'""".format(p0, p1))

    countdown -= 1 

Есть ли лучший способ создать оператор sql или есть способ сгенерировать строки с переменными, которые могут содержать двойные кавычки и / или апострофы?

Если вы очищаете мой сайт, и у меня есть значение столбца, такое как Robert'); DROP TABLE Importantstuff; --, которое обманом заставляет ваш код удалять данные целой таблицы… разве это имеет для вас значение?

abarnert 10.07.2018 04:27
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
43
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы никогда не захотите создавать операторы SQL, вручную цитируя такие вещи.

Почти всегда ответ - использовать параметры SQL. В таких случаях, когда даже имя таблицы является динамической строкой, вы не можете этого сделать.

Вот почему в большинстве библиотек SQL есть функция для вставки значений в кавычки или экранирования вручную. К сожалению, главным исключением является sqlite3.

Итак, вам нужно написать свою собственную функцию экранирования. Как объясняет документы:

A string constant is formed by enclosing the string in single quotes ('). A single quote within the string can be encoded by putting two single quotes in a row - as in Pascal. C-style escapes using the backslash character are not supported because they are not standard SQL.

Так:

def esc(s):
    return "'{}'".format(s.replace("'", "''"))

И теперь вам нужно вручную вызывать его везде, где есть строковое значение:

string = string + ("""{} = '{}' AND """.format(pair[0], esc(pair[1])))

В качестве побочного примечания, вы, кажется, немного запутались в разнице между строковыми литералами и строковыми значениями. Все эти литералы создают идентичную строку формата:

'{} = \'{}\' AND '
"{} = '{}' AND "
"""{} = '{}' AND """

Итак, когда вы вызываете format в этой строке, не имеет значения, с какой из них вы начали. Биты {} просто заменяются содержимым аргументов format. Если в этих аргументах есть кавычки, format просто скопирует кавычки, и ничто из того, что вы можете сделать со строковым литералом для строки формата, не изменит этого. Вам нужно исправить аргументы как строковые значения.


В любом случае, при дальнейшем размышлении, вы, вероятно, используете здесь параметры SQL может - не вместо format, как обычно, а в дополнение к этому. И тогда вы не должны беспокоиться о том, чтобы вручную экранировать вещи, потому что строки, которые вы используете format, не нуждаются в экранировании, а только значения столбцов, которые.

Что вам нужно сделать, так это создать строку плюс список. Например:

whereparams, whereargs = []
for col, val in col_val:
    whereparams.append('{} = ?'.format(name))
    whereargs.append(val)
whereclause = ', '.join(whereparams)
# ...
sql = '''SELECT {rw} FROM {tbl} WHERE {wc}'''.format(
    rw=row, tbl=table, wc=whereclause)

Вы можете выполнить запрос (сейчас или где-то в будущем) следующим образом:

cursor.execute(sql, whereargs)

… Зная, что последовательность whereargs имеет в точности те аргументы, которые соответствуют значениям ? в операторе SQL, в том же порядке.

Первый вариант работает, когда я удаляю одинарные кавычки из строки: def esc(s): return "{}".format(s.replace("'", "''"))

user10056529 10.07.2018 04:23

Другие вопросы по теме