如何在 pymongo 中正确设计正则表达式?
Posted
技术标签:
【中文标题】如何在 pymongo 中正确设计正则表达式?【英文标题】:How to correctly design a regular expression in pymongo? 【发布时间】:2019-10-15 06:30:07 【问题描述】:我使用 python 3.7.1(默认,2018 年 12 月 14 日,19:28:38)和 pymongo 3.7.2。
在 mongodb 中这有效:
db.collection.find(
$and:[
"field":$regex:"bon?",
"field":$not:$regex:"bon souple",
"field":$not:$regex:"bon léger"
]
)
所以在 pymongo 我做了同样的事情:
db.collection.find(
"$and":[
"field":"$regex":"bon?",
"field":"$not":"$regex":"bon souple",
"field":"$not":"$regex":"bon léger"
]
)
但它表示pymongo.errors.OperationFailure: $regex has to be a string
。
所以我按照here的建议尝试了这个:
liste_reg=[
'field': '$regex': '$not': re.compile('bon souple'),
'field': '$regex': '$not': re.compile('bon léger'),
'field': '$regex': re.compile('bon?')
]
rslt=list(
db.collection.find("$and":liste_reg)
)
我注意到即使没有特殊字符也表示相同的错误:
liste_reg=[
'field': '$regex': '$not': re.compile('bon souple') #where no special char is present
]
rslt=list(
db.collection.find("$and":liste_reg)
)
所以我尝试使用"/"
作为:
liste_reg=[
'field': '$regex': '$not':'/bon souple/' #where no special char is present
#even tried re.compile('/bon souple/')
]
rslt=list(
db.collection.find("$and":liste_reg)
)
同样的错误pymongo.errors.OperationFailure: $regex has to be a string
仍然出现。
我能做什么?
我对解决方案研究的一些更新
问题的核心似乎在于$not
,因为当我这样做时:
liste_reg=['field': '$regex': 'bon?']
rslt=list(
db.collection.find("$and":liste_reg)
)
len(rslt)#gives 23 013, what is ok.
没有错误。
一些示例
按照 Emma 的要求,我可以提供一个示例,它会在 mongo 中明确我的请求。 通常,我必须在现场使用这些方式:
秒 très léger 莱热 bon léger 好 便当 双人 très 汤 整理 大声 très Lourd 深刻对我来说主要问题是我的蜘蛛没有正确解析,因为我没有为此编写足够强大的脚本。 我得到的不是仅仅“bon”,而是这样的结果:
"_id":"ID1",
"field":"bon\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\tnon",
...
这是许多其他错误解析之间的示例。
所以这就是为什么我想要以"bon?"
开头但不是"bon souple"
或"bon léger"
的结果,因为它们有正确的值,没有\n
或\t
。
作为样本:
["_id":"ID1",
"field":"bon\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\tnon",
"_id":"ID2",
"field":"bon\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tpremière",
"_id":"ID3",
"field":"bon\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t2ème",
"_id":"ID4",
"field":"bon souple",
"_id":"ID5",
"field":"bon léger"]
【问题讨论】:
@Emma 我用你所问的样本做了更新。或者至少我认为你问的是什么。 @Emma 正如您在演示中所说的那样,它可以在其中工作。但是,我无法解释为什么,当我在 robo3tdb.collection.find("field":$regex:"bon[^\s].+")
的 mongo shell 中编写此代码时,出现的第一个文件是 "_id" : "364714",..., "field" : "bon léger"
。我查看了查看文档,看看它是不是像"bon\t\t\t\t\nléger"
这样的异常,实际上这真的是"bon léger"
。在我的 mongo shell 中,它考虑了空格键。除了在 pymongo 中,我还获得了一个带有 len(list(db.geny_rapp.find('etat_terrain': '$regex': "bon[^\s].+")))
的空列表。
@Emma 老实说,我有另一种方法可以回答我的问题,但是没有正则表达式,这更复杂,我使用集合和集合上的操作:setA-setB -> 我想要的集合。但正如我所说,它更复杂,这不是目标。
【参考方案1】:
在这里,我们也许可以解决这个问题,也许不使用$not
功能。例如,如果我们不希望有bon souple
或bon léger
,它们是bon
后跟一个空格,我们可以使用类似于以下的表达式:
"bon[^\s].+"
DEMO
我不太确定我们希望在这里提取什么,但我只是猜测我们可能想要滑动bon
后面不带空格的值,并且在"
之间。
此外,我们可能希望研究正则表达式查询要求并在必要时调整我们的表达式,例如转义或使用捕获组:
(bon[^\s].+)
或:
"(bon[^\s].+)"
或:
\"(bon[^\s].+)\"
或:
([\s\S]*?)\"(bon[^\s].+)\"
DEMO
正则表达式电路
jex.im 可视化正则表达式:
我不太确定这是否是我们想要的或者是否相关,但根据documentation,我们可以尝试使用:
name: $regex: /([\s\S]*?)\"(bon[^\s].+)\"/, $options: "mi"
或:
name: $regex: '([\s\S]*?)\"(bon[^\s].+)\"', $options: "mi"
db.collection.find
db.collection.find("field": $regex: /(bon[^\s].+)/, $options: "mi" )
或:
db.collection.find("field": $regex: /(bon[^\s].+)/, $options: "si" )
参考:
PyMongo $in + $regex
Performing regex Queries with pymongo
【讨论】:
执行db.collection.find("field":$regex:"\"(bon[^\s].+)\"" )
或db.collection.find("field":$regex:"([\s\S]*?)\"(bon[^\s].+)\"")
给出:Fetched 0 record(s) in 55ms
。注意我输入了"\"(bon[^\s].+)\""
而不是\"(bon[^\s].+)\"
,([\s\S]*?)\"(bon[^\s].+)\"
也一样,因为它会在 mongo shell 中引发错误。
db.collection.find("field": $regex: /([\s\S]*?)\"(bon[^\s].+)\"/, $options: "mi" )
没有错误,但结果为 0。【参考方案2】:
尝试使用带有否定前瞻的字符串文字。只要您在 'bon' 后面有回车符 (\r),下面的示例就应该可以工作。
import re
bon = re.compile(r'bon(?=\r)')
db.collection.find('field': bon)
【讨论】:
len(list(db.collection.find('field': '$regex': re.compile(r'bon(?=\r)'))))
给了我 19 个文件。虽然我期望 22242。我想我会用另一种方式来回答我的问题,而不仅仅是正则表达式并使用集合对象的属性。
可能更容易清理您的数据。 bon_dirty = 'bon\r\n\t' bon_clean = bon_dirty.strip()
好吧,我转储了我的收藏,现在很清楚,这就是我所期望的。它返回的文件数量与使用 $not 的 mongo 相同。但是为什么re.compile()
对我不起作用而对others 起作用仍然是个谜。【参考方案3】:
我刚刚遇到了同样的问题。
尝试这样做:
liste_reg=[
'field': '$not': re.compile('bon souple'),
'field': '$not': re.compile('bon léger'),
'field': '$regex': re.compile('bon?')
]
rslt=list(
db.collection.find("$and":liste_reg)
)
我刚刚删除了查询的$regex
部分。
背景
我尝试做 item["type"]: "$not": item['name']
并且 pymongo 返回了 $not needs a regex or a document
错误。
所以,我尝试了:item["type"]: "$not": "$regex": item['name']
并且 pymongo 返回了 $not cannot have a regex
错误。
我找到了这个 SO https://***.com/a/20175230/9069964,这就是最终对我有用的方法:
item_name = item["name"]
item["type"]: "$not": re.compile(item_name)
我不得不放弃“$regex”部分并给“$not”我的正则表达式内容。
【讨论】:
太好了!它有效,这完全符合我的代码的精神。此外,它还提供了使用 '$not' 而不避免它的方法。以上是关于如何在 pymongo 中正确设计正则表达式?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用正则表达式查询 pymongo 以获取仅包含数字的值