django:iregex区分大小写

时间:2017-03-20 14:35:40

标签: mysql regex django

使用这两个查询一个接一个地访问db(MySQL),得到不同的结果:

test1 = Agreement.objects.filter(pk=152, company__iregex='СитиСтро(и|й)')
test2 = Agreement.objects.filter(pk=152, company__iregex='ситистро(и|й)')

test1 <QuerySet [<Agreement: Agreement object>]>
test2 <QuerySet []>

如果字段'“СитиСтрой”'

,则显示实际值

现在我很确定西里尔字母会搞砸了,因为拉丁字母表中的记录很好用,但我不知道怎么解决这个问题(bug?)。这里有什么建议吗?

PS我做了双重检查,这里没有混淆与英文和俄文相似的C字母,但有不同的字母代码。

更新 检查了Django发送给Mysql的sql。

('SELECT `dbbs_app_agreement`.`id`, `dbbs_app_agreement`.`company`, '
 'FROM `dbbs_app_agreement` WHERE (`dbbs_app_agreement`.`company` REGEXP '
 'СитиСтро(и|й) AND `dbbs_app_agreement`.`id` = 152)')

似乎很好。 尝试使用

直接从phpmyadmin查询表
SELECT `dbbs_app_agreement`.`id`, `dbbs_app_agreement`.`company` FROM `dbbs_app_agreement` WHERE (`dbbs_app_agreement`.`id` = 152 AND `dbbs_app_agreement`.`company` REGEXP 'С')

哪个有效,但是

SELECT `dbbs_app_agreement`.`id`, `dbbs_app_agreement`.`company` FROM `dbbs_app_agreement` WHERE (`dbbs_app_agreement`.`id` = 152 AND `dbbs_app_agreement`.`company` REGEXP 'с')

同时没有。

正如下面提到的@AndreyShipilov,在数据库中从头开始用utf8_unicode_ci整理创建了一个新表,插入了有问题的值(ООО“СитиСтрой”)并尝试了phpmyadmin的这两个查询:

SELECT `company`.`id`, `company`.`company` FROM `company` WHERE (`company`.`id` = 0 AND `company`.`company` REGEXP 'с')
SELECT `company`.`id`, `company`.`company` FROM `company` WHERE (`company`.`id` = 0 AND `company`.`company` REGEXP 'С')

第二个有效,第一个没有。 真的很奇怪。

UPDATE2 构成查询的初始代码如下所示:

query_ka_name = reduce(operator.and_,
(Q(company__iregex=r'(([^\w]|^){i}([^\w]|$))'.format(i=re.sub(r'и|й', '(и|й)', item, flags=re.IGNORECASE)))

目的是检查数据库记录是否与扫描中识别的关键字数组相对应,作为公司名称。由于扫描仪非常糟糕,区别于我,并且db记录超出了我的控制范围,我添加了一些小东西来将这些字母视为一个。

现在代码看起来像这样:

query_ka_name = reduce(operator.and_, (Q(company__iregex=tambourine(item)) for item in ka_name_listed))

def tambourine(string):
    string = re.sub(r'и|й', '(и|й)', string, flags=re.IGNORECASE)
    output = ''
    for char in string:
        if char.isalpha():
            output = '{o}({u}|{l})'.format(o=output, u=char.upper(), l=char.lower())
        else:
            output = '{o}{c}'.format(o=output, c=char)
    output = r'(([^\w]|^){i}([^\w]|$))'.format(i=output)
    return output

相比之下,这可能很慢,但至少它有效。 仍然非常欣赏这个问题的解决方案。

2 个答案:

答案 0 :(得分:1)

  • &#34; LATIN SMALL LETTER C不被视为与#34; CYRILLIC SMALL LETTER ES&#34;。
  • 相同
  • Ditto for&#34; CYRILLIC SMALL LETTER I&#34;和&#34; CYRILLIC SMALL LORTTER简短I&#34;
  • MySQL REGEXP使用字节而非字符。因此,REGEXP只能使用无重音的英文字母;没有西里尔字母可以(可靠地)工作。
  • MariaDB 10.0.5&#39; REGEXP应该做得更好。参考:https://mariadb.com/kb/en/mariadb/pcre/

答案 1 :(得分:0)

我建议切换到Postgres数据库,处理非拉丁符号非常好。

试图在我的Django 1.10和Postgres 9.6设置上重现您的问题。

from django.contrib.auth.models import User users = User.objects.filter(username__iregex='Сосницки(и|й)') users <QuerySet [<User: Сосницкий>, <User: сосницкий>, <User: сосницкии>, <User: СоСницкии>]>

似乎正在发挥作用。