【问题标题】:MySQL string comparison with special charactersMySQL字符串与特殊字符的比较
【发布时间】:2015-11-06 09:45:31
【问题描述】:

我创建了一个与数据库中的名称列表匹配的自动完成功能。

我正在使用的数据库包含大量带有特殊字符的名称,但最终用户很可能会使用这些名称的英文等价物进行搜索,例如Bela Bartok 对应Béla BartókDvorak 对应Dvořák 等。目前,进行英文搜索没有返回结果。

我遇到过线程说解决这个问题的方法是将您的 MySQL 排序规则更改为 utf8(我没有这样做)。

我认为这可能是因为我使用了utf8_unicode_ci,但是会得到我想要的结果的那个是utf8_general_ci。后者的问题是所有的 cmets 都说不再使用它。

有谁知道我该如何解决这个问题?

【问题讨论】:

  • 不同的字符保持不同的字符。没有“特殊字符”之类的东西。他们应该有什么特别之处?是不是有些人不太了解他们?
  • @arkascha 如果它们不是世界上大多数人使用的 ASCII 码,那么有些人可能会争辩说它是一个“特殊字符”。例如。在世界杯期间,每个人最喜欢的德国人厄齐尔的名字都被 BBC 拼成了厄齐尔,因为这是音译
  • @arkascha 当你谷歌搜索 ozil 时你会得到 Özil
  • 确实如此,但这并不意味着字符完全相同。它也没有解释变音符号“Ö”的“特殊”之处。解决方案确实是使用合适的排序规则,因为排序规则定义了字符到其他字符的“映射”。它以相同的方式制作或处理字符。那会产生非常有趣的效果。

标签: mysql special-characters collation


【解决方案1】:

如果您知道特殊字符列表以及普通英语中的等价字符,则可以执行以下操作:

  1. 小写字符串
  2. 用小写等效字符替换字符
  3. 搜索“纯英语”列

您将需要使用 MySQL 的全文搜索来搜索文本,或者想出一个本地解决方案来处理它。

【讨论】:

    【解决方案2】:

    刚刚使用 utf8_general_ciutf8_unicode_ci 排序规则进行了测试,在这两种情况下都非常有效。

    遵循我用来运行测试的 MySQL 代码:

    CREATE TABLE `test` (
     `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
     `text` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
     PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
    INSERT INTO `test` (`id`, `text`) VALUES (NULL, 'Dvořák'), (NULL, 'Béla Bartók');
    
    SELECT * FROM `test` WHERE `text` LIKE '%dvorak%';
    

    以上SELECT语句返回:

    id      text
    --------------
    1       Dvořák
    

    注意:在测试期间,我将所有排序规则设置为所需的排序规则。数据库排序规则、表排序规则和列排序规则。

    可能是您的 PHP 应用程序中存在错误?

    【讨论】:

    • 如果它对您有用,那么 PHP 中很可能存在错误。我刚刚看到您对我尚未设置的列排序规则的编辑。我会测试一下。谢谢
    • 我建议你在你的环境中尝试我的 MySQL sn-p 而不通过 PHP。只是通过 shell 的 MySQL。如果它像我一样工作(它会!)那么你可以排除是 MySQL 问题:-)
    • 你说得最对。以上在 PHP 之外工作得非常好,我的查询也是。但是,我只是测试了其他东西:因为我需要有一个单词边界,所以我使用了 regexp 而不是 like,在这种情况下 not 不起作用!
    【解决方案3】:

    我找到了解决问题的方法。将排序规则更改为 utf8_unicode_ci 效果很好。我的问题是我需要在查询中使用REGEXP 而不是LIKE,但是REGEXP 在这种情况下显然不起作用!

    简而言之,将排序规则更改为 utf8_unicode_ci 将允许您使用 =LIKE 比较 Dvorak 和 Dvořák,但不能使用 REGEXP 等效项之一。

    【讨论】:

    • 这对我来说似乎不是一个解决方案。您只是说您的代码不起作用,因为您使用的是REGEXP 而不是LIKE。那么解决方案是什么? REGEXP 怎么可能达到同样的目标?如果不可能,您应该在答案中写下,也许指向一些官方文档。
    • @francescoCasula 是的,这是我的代码错误
    【解决方案4】:

    首先,让我们看看数据是否存储正确。做

    SELECT name, HEX(name) FROM ... WHERE ...;
    

    Béla 可能会出现(忽略空格)

    42 C3A9 6C 61 -- if correctly encoded with utf8 (é = C3A9)
    42  E9  6C 61 -- if encoded with latin1 (é = E9)
    

    “排序规则”(utf8_general_ci 或 utf8_unicode_ci)对您提供的示例没有影响。两者都踩é = e。见extensive list of equivalences for utf8 collations

    确定编码后,我们就可以开药了。

    【讨论】:

      【解决方案5】:

      从 Rick James 那里得到提示,使用:

      SELECT * FROM `test` WHERE HEX(`column`) = HEX('Dvořák');
      

      应该可以。如果您需要不区分大小写的查询,那么除了 HEX 检查之外,您还需要降低/提高两边。

      【讨论】:

        【解决方案6】:

        更新的排序规则是 utf8mb4_unicode_520_ci。

        注意,它不适用于 utf8mb4_unicode_ci。在此处查看比较:https://stackoverflow.com/a/59805600/857113

        【讨论】:

          猜你喜欢
          • 2015-07-15
          • 1970-01-01
          • 1970-01-01
          • 2019-08-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-02
          • 1970-01-01
          相关资源
          最近更新 更多