【发布时间】:2016-11-14 20:21:23
【问题描述】:
我在尝试使用 glob 模式查询 db 时遇到问题。
我认为也许 glob 可以翻译成正则表达式,我知道 I can query db using regex。我本来打算自己翻译的,但我发现 python 有 fnmatch 可以做到这一点,明确的函数 translate
fnmatch.translate(模式)
返回转换为正则表达式的 shell 样式模式,以便与 re.match() 一起使用。
所以我尝试将两者结合起来,但是......
>>> from vte.models import VTE
>>> import fnmatch
>>> regex = fnmatch.translate('19*')
>>> regex
'19.*\\Z(?ms)'
>>> VTE.objects.filter(ipaddr__regex=regex)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 234, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 258, in __iter__
self._fetch_all()
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 1074, in _fetch_all
self._result_cache = list(self.iterator())
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 52, in __iter__
results = compiler.execute_sql()
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 848, in execute_sql
cursor.execute(sql, params)
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/utils.py", line 95, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/var/www/vtfx/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
DataError: invalid regular expression: quantifier operand invalid
我不明白错误信息。
根据 django 的文档,应该在 postgresql(顺便说一下,我正在使用的 db)中翻译成这样的东西
SELECT ... WHERE ipaddr ~ '19.*\\Z(?ms)';
Here it is the ~ operator documentation.
所以我尝试对translate() 返回的正则表达式稍作修改,删除? 字符时不会抛出错误。
然后我想,如果没有最后一部分 \\Z(?ms),也许 glob->regex 翻译可以正常工作,但我不确定,我可能会遗漏一些东西。
回顾:
- 这会引发错误
19.*\\Z(?ms) - 这不会引发错误
19.*\\Z(ms) - 我认为这可以按预期工作
19.*
所以新的代码应该是这样的
>>> VTE.objects.filter(ipaddr__regex=regex.replace('\\Z(?ms)', ''))
[<VTE: 192.168.56.100>]
在做.replace('\\Z(?ms)', '') 时我错过了什么?为什么这是必要的?这是一个好的解决方案吗?
【问题讨论】:
-
fnmatch不会将 glob 表达式转换为 Python 正则表达式吗?每个人的正则表达式语法都有点不同,支持的功能也各不相同。我猜(?ms)正在尝试将/m和/s选项应用于正则表达式,而PostgreSQL 不支持(?...)。您可能正在寻找的 (PostgreSQL) 正则表达式只是'19.*'。不是 Python 人,所以我没有给你答案,只是一些起点。 -
很好,这确实很有帮助。另外,
\\Z似乎与$(行尾)相同,所以也许我应该像这样替换.replace('\\Z(?ms)', '$'),那么正则表达式应该是(我认为)'19.*$' -
一些正则表达式引擎通过同时使用
\Z(或\z)和$来区分字符串的结尾和行的结尾,\A与^的字符串开头类似和行首。 -
确认/澄清提供的信息:PostgreSQL 和 Python 都区分“行尾”(
$)和“字符串尾”(\Z)。字符串(?ms)编码嵌入式选项,PostgreSQL 仅在正则表达式的开始 处支持。例如,(?ms)19.*\\Z是一个有效的 PostgreSQL 正则表达式(参见 postgresql.org/docs/9.3/static/…)。 -
这很有帮助,谢谢!
标签: python regex django postgresql glob