【问题标题】:Comparing strings in PHP the same way MySQL does以与 MySQL 相同的方式比较 PHP 中的字符串
【发布时间】:2010-10-03 00:43:35
【问题描述】:

我将 varchar 存储在 utf8 MySQL 表中并使用 utf8_general_ci 排序规则。我在 varchar 上有一个唯一索引。我想在 PHP 中做一个字符串比较,这相当于 MySQL 对索引所做的事情。

一个具体的例子是,我希望能够在这种情况发生之前检测到“a”被认为等同于 PHP 中的“À”:

mysql> insert UniTest (str) values ('a');                                   
Query OK, 1 row affected (0.00 sec)

mysql> insert UniTest (str) values ('À');                                   
ERROR 1062 (23000): Duplicate entry 'À' for key 1

【问题讨论】:

    标签: php mysql utf-8 collation mysql-error-1062


    【解决方案1】:

    通过向 MySQL 提交如下查询,让 MySQL 完成工作是否合理:

    SELECT CASE WHEN '$a' = '$b' THEN 1 ELSE 0 END
    


    编辑后澄清:

    您可以一次性遍历整个感兴趣的笛卡尔字符集,并构建一个标准的 php 等价集关联数组。

    对于 $charset {中的每个 $char1 对于 $charset {中的每个 $char2 $charmatch[$char1][$char2] = mysqlTestMatch($char1, $char2)); } }

    然后你需要逐个字符地测试每个字符串,看看 a) 它们是否相同,或者如果不一样,b) 它们是等价的。

    【讨论】:

    • 出于许多不同的原因,我使用大量字符串执行此操作,因此我想避免使用数据库。
    【解决方案2】:

    使用 intl 的 Collat​​or 或 Transliterator。

    $s1 = 'a';
    $s2 = 'À';
    
    var_dump(
        is_same_string($s1, $s2),
        $s1 === transliterator_transliterate('Any-Latin; Latin-ASCII; Lower()', $s2)
    );
    
    function is_same_string($str, $str2, $locale = 'en_US')
    {
        $coll = collator_create($locale);
        collator_set_strength($coll, Collator::PRIMARY);  
        return 0 === collator_compare($coll, $str, $str2);
    }
    

    【讨论】:

      【解决方案3】:

      所以,如果我理解正确,您想在 PHP 中进行类似的比较,就像在 MySQL 中检查 UTF-8 通用索引检查一样?

      最简单的方法是创建一个辅助函数,根据 MySQL 使用的 utf8_general_ci 规则转换字符串,主要是将某些字母转换为基本字母。

      此处列出了该 MySQL 排序规则的规则:

      http://www.collation-charts.org/mysql60/mysql604.utf8_general_ci.european.html
      

      例如,如果您向下滚动一点到左侧的“金色 A”,您会看到所有转换为该 A 的字符。

      给定一个辅助函数,例如utf8g_to_ascii(),您可以编写一个函数:

      function utf8_compare($s1, $s2) {
         $a = utf8g_to_ascii($s1);
         $b = utf8g_to_ascii($s2);
         return strcmp( $a, $b );
      }
      

      我会模仿我的代码:

      http://dev.splitbrain.org/view/darcs/dokuwiki/inc/utf8.php
      

      【讨论】:

        【解决方案4】:

        排序规则与存储无关。您需要设置字符集来确定存储编码。排序规则控制应该如何进行比较和排序。排序规则必须支持字符集,否则与字符集无关。

        要回答您的问题,您可以使用iconv 转写文本,然后进行比较。例如:

        function compare($s1, $s2) {
          return strcmp(
            iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s1),
            iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s2));
        }
        

        这基本上是 MySql 将为您做的事情,尽管它可能更快,并且它的排序表可能与 ISO-8859-1//TRANSLIT 略有不同。不完全确定。

        不过,正如其他人已经建议的那样,使用该数据库可能会更容易。

        【讨论】:

        • 我编辑了问题以准确反映排序规则与存储字符集。你能给我一个使用 mb_string 来实现它的例子吗?我在文档中没有看到 mb_strcmp。
        • 我犯了一个错误 - 你需要使用 iconv - 而不是 mb_string。我已经编辑了我的答案。
        • 这越来越近了。 //TRANSLIT 技巧很好,但正如你提到的,ISO-8859-1 不是我需要的。 MySQL 正在使用看起来像这样的排序规则,我需要以某种方式模拟它:collation-charts.org/mysql60/…
        • 如果 Iconv 相当有限的功能不适合你,你可以试试这个扩展:derickrethans.nl/translit.php 或者这个(纯 php):sitepoint.com/blogs/2006/03/03/…
        • 两者都允许您使用用户定义的音译数据库。如果您需要完全匹配,您可以复制 MySqls。但是首先使用数据库可能会更容易;)
        【解决方案5】:

        为什么不让 MySQL 决定是否已经存在具有相同 key 的记录?

        您可以运行SELECT 查询来询问是否已经存在具有此属性的记录:

        SELECT 1
        FROM UniTest
        WHERE str = "À"
        

        或者你只是尝试插入新记录并使用函数mysql_error()mysql_errno()查看是否发生错误。

        【讨论】:

          猜你喜欢
          • 2015-11-23
          • 2014-02-23
          • 1970-01-01
          • 2011-08-17
          • 1970-01-01
          • 2015-11-06
          • 2017-11-10
          • 1970-01-01
          相关资源
          最近更新 更多