【问题标题】:Whole-word match only in Django query仅在 Django 查询中进行全字匹配
【发布时间】:2013-02-06 11:57:21
【问题描述】:

我正在尝试编写一个仅匹配整个单词的 Django 查询。根据here 的回答,我尝试过类似的方法:

result = Model.objects.filter(text__iregex='\bsomeWord\b')

但这并没有返回预期的结果。我也试过了

result = Model.objects.filter(text__iregex=r'\bsomeWord\b')

无济于事。我的最终目标是也能够传入一个字符串变量,例如:

result = Model.objects.filter(text__iregex=r'\b'+stringVariable+r'\b')

result = Model.objects.filter(text__iregex=r'\b %s \b'%stringVariable)

但现在我什至无法让它与原始字符串一起使用。我正在使用 PostgreSQL。

【问题讨论】:

    标签: regex django postgresql django-queryset


    【解决方案1】:

    当你使用 PostgreSQL 时,使用“\y”而不是“\b”,这是因为 Django 将你的正则表达式直接传递给 PostgreSQL——所以你的RegEx 需要与之兼容。您应该可以从psql 执行它们而不会出现任何问题。

    result = Model.objects.filter(text__iregex=r"\y{0}\y".format(stringVariable))
    

    https://www.postgresql.org/docs/9.1/functions-matching.html#POSIX-CONSTRAINT-ESCAPES-TABLE

    【讨论】:

    • Django 不会将 PCRE 转换为 PostgreSQL 正则表达式(请参阅:bit.ly/ZtpbgH)。所以你只需要使用 PostgreSQL 的原生正则表达式,看这里:bit.ly/ZtpojU
    • 这行得通。感谢您添加关于\y 的解释。至于'{0}'.format(stringVariable) 部分,这只是'%s'%stringVariable 的另一种写法吗?两者似乎都对我有用。
    • 是的,实际上他们都做同样的事情。我只使用 .format() 方式,因为 Python 3 需要它 (python.org/dev/peps/pep-3101)。
    【解决方案2】:

    你也许可以通过删除正则表达式并使用一些 django 查找来获得一些东西

    result = Model.objects.filter(Q(text__contains=' someword ') |
                                  Q(text__contains=' someword.') |
                                  Q(text__istartswith = 'someword.' |
                                  Q(text__istartswith = 'someword.' |
                                  Q(text__iendswith = 'someword')
    

    有关文档,请参阅 here

    我意识到这不是那么优雅(但如果您不是正则表达式的粉丝,那么维护起来很容易)。

    【讨论】:

    • 因为这不会执行全字匹配;例如,如果我执行text__contains='tart',我会选择start 这样的结果。
    • 我的错 - 我显然对 sql 不够熟悉,无法知道“全词匹配”意味着特定的东西。无论如何,我已经更新了我的答案以改进它。
    • 易于维护?有很多情况你没有涵盖(在()、逗号等之间)。
    • 如果您不喜欢正则表达式,则易于维护。你不需要知道 django 或 python 来阅读这个 - 但我必须引用任何解决这个问题的正则表达式。是的,这并不能涵盖所有内容 - 只有当您确信文本仅包含该语言的一个子集时,它才会起作用。
    【解决方案3】:

    我在尝试使用与 Perl 兼容的转义序列 \b 匹配单词边界时遇到了同样的问题。我的后端数据库是 MySQL。

    我通过字符类表达式[[:space:]]解决了这个问题,例如

            q_sum = Q()
            search_list = self.form.cleaned_data['search_all'].split(' ');
            for search_item in search_list:
                search_regex = r"[[:space:]]%s[[:space:]]" % search_item
                q_sum |= Q(message__iregex=search_regex)
            queryset = BlogMessages.objects.filter(q_sum).distinct()
    

    【讨论】:

    • 这不包括标点符号。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-20
    • 2018-02-23
    • 2012-07-09
    • 1970-01-01
    • 2013-09-22
    • 2011-08-19
    相关资源
    最近更新 更多