【问题标题】:Can I query the DB using a glob pattern?我可以使用 glob 模式查询数据库吗?
【发布时间】: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


【解决方案1】:

基于我的问题的 cmets,我最终做了以下操作

import fnmatch
globex = ......
regex = '^{}'.format(fnmatch.translate(globex).replace('\\Z(?ms)', '$'))
VTE.objects.filter(ipaddr__regex=regex)

这似乎与 postgresql 和 javascript 正则表达式实现兼容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 2010-11-19
    相关资源
    最近更新 更多