Вы должны сделать distinct
вызов на курсоре , возвращенном из find
, а не в коллекции:
tags = db.mycoll.find({"category": "movie"}).distinct("tags")
Это потому, что модуль python re
довольно слаб и не поддерживает подпрограммы и рекурсию Вместо этого попробуйте модуль pypi regex
. Это скомпилирует ваше регулярное выражение.
Вы нашли регулярное выражение, использующее синтаксис, который модуль стандартной библиотеки Python re
не поддерживает.
Когда вы посмотрите на ссылку regex101, вы увидите, что шаблон работает при использовании библиотеки PRCE , а проблемный синтаксис (?R)
, который выдает ошибку, использует функцию под названием [ 1114] рекурсии . Эта функция поддерживается только подмножеством механизмов регулярных выражений .
Вы можете установить библиотеку regex
, альтернативный механизм регулярных выражений для Pythont, который явно поддерживает этот синтаксис:
>>> import regex
>>> pattern = regex.compile(r'\{(?:[^{}]|(?R))*\}')
>>> pattern.findall('''\
... This is a funny text about stuff,
... look at this product {"action":"product","options":{...}}.
... More Text is to come and another JSON string
... {"action":"review","options":{...}}
... ''')
['{"action":"product","options":{...}}', '{"action":"review","options":{...}}']
Другой вариант - просто попытаться декодировать любой раздел который начинается с {
с использованием метода JSONDecoder.raw_decode()
; см. Как использовать модуль 'json' для чтения по одному объекту JSON за раз? для примера подхода. В то время как рекурсивное регулярное выражение может найти JSON- подобный тексту , подход декодера позволит вам извлечь только действительный текст JSON.
Вот функция генератора, которая делает именно это:
from json import JSONDecoder
def extract_json_objects(text, decoder=JSONDecoder()):
"""Find JSON objects in text, and yield the decoded JSON data
Does not attempt to look for JSON arrays, text, or other JSON types outside
of a parent JSON object.
"""
pos = 0
while True:
match = text.find('{', pos)
if match == -1:
break
try:
result, index = decoder.raw_decode(text[match:])
yield result
pos = match + index
except ValueError:
pos = match + 1
Демонстрация:
>>> demo_text = """\
This is a funny text about stuff,
look at this product {"action":"product","options":{"foo": "bar"}}.
More Text is to come and another JSON string, neatly delimited by "{" and "}" characters:
{"action":"review","options":{"spam": ["ham", "vikings", "eggs", "spam"]}}
"""
>>> for result in extract_json_objects(demo_text):
... print(result)
...
{'action': 'product', 'options': {'foo': 'bar'}}
{'action': 'review', 'options': {'spam': ['ham', 'vikings', 'eggs', 'spam']}}