【问题标题】:PHP - sort function with 'SORT_LOCALE_STRING' return incorrect resultPHP - 带有“SORT_LOCALE_STRING”的排序函数返回不正确的结果
【发布时间】:2018-01-07 06:22:38
【问题描述】:


我有一些 VARCHAR 类型的 MySQL 记录,排序规则是 utf8mb4_unicode_ci

Tiếng Việt Nam
Tiếng Hoa Kỳ
Tiếng Anh
Tiếng Nhật
Tiếng Hàn Quốc
Tiếng Thái Lan

然后,我使用 PHP 按字母顺序对它们进行排序:

$languages = [
        'Tiếng Việt Nam',
        'Tiếng Hoa Kỳ',
        'Tiếng Anh',
        'Tiếng Nhật',
        'Tiếng Hàn Quốc',
        'Tiếng Thái Lan',
    ];
setlocale(LC_COLLATE, 'vi');
sort($languages, SORT_LOCALE_STRING);

这样调用var_dump($languages)时的结果:

array (size=6)
  0 => string 'Tiếng Anh' (length=11)
  1 => string 'Tiếng Hoa Kỳ' (length=16)
  2 => string 'Tiếng Nhật' (length=14)
  3 => string 'Tiếng Thái Lan' (length=17)
  4 => string 'Tiếng Việt Nam' (length=18)
  5 => string 'Tiếng Hàn Quốc' (length=22)

'Tiếng Hàn Quốc'的顺序有问题,结果应该是这样的:

array (size=6)
  0 => string 'Tiếng Anh' (length=11)
  1 => string 'Tiếng Hàn Quốc' (length=19)
  2 => string 'Tiếng Hoa Kỳ' (length=16)
  3 => string 'Tiếng Nhật' (length=14)
  4 => string 'Tiếng Thái Lan' (length=17)
  5 => string 'Tiếng Việt Nam' (length=18)

然后,我通过直接输入 MySQL(使用 HeidiSQL)将现有的 'Tiếng Hàn Quốc' 替换为另一个(也是 'Tiếng Hàn Quốc')。最后,我得到了预期的结果。

我觉得这里不一样:

string 'Tiếng Hàn Quốc'(length=22)
string 'Tiếng Hàn Quốc'(length=19)

问题是: 这里的问题根源是什么? 如何在 MySql 或 PHP 代码中解决此问题以获得预期结果,而无需查找和替换 MySQL 中所有不正确的值?

谢谢。

【问题讨论】:

  • 我建议通过 ord() 函数逐个符号解析问题字符串,并与普通字符串进行比较。如果代码不匹配,请将其替换为正确的符号
  • 差异通常是由于某些字符,例如 无论是单个 unicode 字符还是带有重音符号的组合字符,在视觉上都是相同的。 Tiếng Việt Nam 降到最后的事实可能表明问题在于 ế 在这种情况下被视为不同的字符。
  • @A.Mikhailov 感谢您的建议,但我认为这种方式很难做到,或者我不理解您的想法。你能用一些示例代码更具体一些吗?
  • @apokryfos:谢谢。我明白你所说的。有没有办法将字符从一种类型解析为另一种类型? 单个 unicode 字符带重音的组合字符,反之亦然。

标签: php mysql collation


【解决方案1】:

简短回答:您需要此排序规则:utf8mb4_vietnamese_ci

长答案:字符串具有不同的 UTF-8 十六进制表示:

Tiếng Hàn Quốc (length=20)  54 69 C3AA CC81 6E 67 48 61 CC80 6E 51 75 C3B4 CC81 63
Tiếng Hàn Quốc (length=17)  54 69  E1BABF   6E 67 48  C3A0   6E 51 75  E1BB91   63

但是,有一个潜在的问题:

C3AA        234=x00EA  [ê]    L  LATIN SMALL LETTER E WITH CIRCUMFLEX
CC81        769=x0301  [́]  NSM  COMBINING ACUTE ACCENT
6E          110=x006E  [n]    L  LATIN SMALL LETTER N

E1BABF     7871=x1EBF  [ế]    L  LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
6E          110=x006E  [n]    L  LATIN SMALL LETTER N

在第一个字符串中,ê 通过单个 utf8 字符(十六进制 C3AA)呈现,accent-n 通过一对 utf8 字符呈现——一个非空格重音符号和字母 n。

在第一个字符串中,重音符号是字母 e 的一部分。我对 utf8 中的越南语编码一无所知,但如果锐音真的应该在字母 n 上,这听起来是“错误的”。

但是,无论如何,这两个字符串与排序规则 utf8mb4_vietnamese_ci(或 utf8_vietnamese_ci)比较相等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多