Выход из Юникода Python для запроса на совпадение (регулярное выражение) RethinkDB - PullRequest
1 голос
/ 30 марта 2019

Я пытаюсь выполнить запрос соответствия rethinkdb с помощью экранированного юникода, предоставленного пользователем, для поиска:

import re
from rethinkdb import RethinkDB

r = RethinkDB()

search_value = u"\u05e5"  # provided by user via flask
search_value_escaped = re.escape(search_value)  # results in u'\\\u05e5' ->
    # when encoded with "utf-8" gives "\ץ" as expected.

conn = rethinkdb.connect(...)

results_cursor_a = r.db(...).table(...).order_by(index="id").filter(
    lambda doc: doc.coerce_to("string").match(search_value)
).run(conn)  # search_value works fine

results_cursor_b = r.db(...).table(...).order_by(index="id").filter(
    lambda doc: doc.coerce_to("string").match(search_value_escaped)
).run(conn)  # search_value_escaped spits an error

Ошибка для search_value_escaped следующая:

ReqlQueryLogicError: Error in regexp `\ץ` (portion `\ץ`): invalid escape sequence: \ץ in:
r.db(...).table(...).order_by(index="id").filter(lambda var_1: var_1.coerce_to('string').match(u'\\\u05e5m'))
                                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         

Я пытался кодировать с помощью "utf-8" до / после re.escape (), но те же результаты с разными ошибками. Что я возиться? Это что-то в моем коде или какая-то ошибка?

РЕДАКТИРОВАТЬ: .coerce_to ('string') преобразует документ в кодированную строку "utf-8". RethinkDB также преобразует запрос в «utf-8», а затем сопоставляет их, следовательно, первый запрос работает, даже несмотря на то, что он выглядит как совпадение unicde внутри строки.

1 Ответ

1 голос
/ 30 марта 2019

Судя по всему, RethinkDB отклоняет экранированные символы Юникода, поэтому я написал простой обходной путь с пользовательским экранированием без реализации собственной логики замены символов (опасаясь, что я должен пропустить один из них и создать проблему безопасности).

import re

def no_unicode_escape(u):
    escaped_list = []

    for i in u:
        if ord(i) < 128:
            escaped_list.append(re.escape(i))
        else:
            escaped_list.append(i)

    rv = "".join(escaped_list)
    return rv

или однострочный:

import re

def no_unicode_escape(u):
    return "".join(re.escape(i) if ord(i) < 128 else i for i in u)

, который дает требуемый результат экранирования «опасных» символов и работает с RethinkDB, как я хотел.

...