在mysql或php中使用utf字符进行排序?最佳解决方案

在mysql或php中使用utf字符进行排序?最佳解决方案,php,mysql,sorting,collation,Php,Mysql,Sorting,Collation,使用MySQL,我选择了一个西班牙语歌曲列表,我想对这些歌曲进行排序。以下是查询返回的名称列表: “德西雷维拉 阿罕布拉 123帕西托斯 África 阿罗兹 分贝 排序后的列表应如下所示: 123帕西托斯 África 阿罕布拉 阿罗兹 “德西雷维拉 分贝 在阅读了所有的研究之后,我得出结论,使用MySQL实现这一点没有合理的方法。我试过排序、字符集等。。。但是这个角色,等等,是不可能的。。。可以根据我想要的结果进行排序。即使是Á也没有按照我想要的方式分类 问题1:这是一个合理的结论吗

使用MySQL,我选择了一个西班牙语歌曲列表,我想对这些歌曲进行排序。以下是查询返回的名称列表:

  • “德西雷维拉
  • 阿罕布拉
  • 123帕西托斯
  • África
  • 阿罗兹
  • 分贝
排序后的列表应如下所示:

  • 123帕西托斯
  • África
  • 阿罕布拉
  • 阿罗兹
  • “德西雷维拉
  • 分贝
在阅读了所有的研究之后,我得出结论,使用MySQL实现这一点没有合理的方法。我试过排序、字符集等。。。但是这个角色,等等,是不可能的。。。可以根据我想要的结果进行排序。即使是Á也没有按照我想要的方式分类

问题1:这是一个合理的结论吗

我相信实现这一点的唯一方法是将结果传递给php中的数组,然后使用自定义函数对数组进行排序。。。所有这些都使用函数usort(需要按值排序,我不关心维护键关联)。类似于此:

function normalize($a, $b) {
  if ($a == $b) {
     return 0;
  }

  return ($a < $b) ? -1 : 1;
}


$tracks = array();

while ($row = $result->fetch_assoc()) {
    $tracks[] = $row;
}

usort($tracks, 'normalize');
函数正常化($a,$b){
如果($a=$b){
返回0;
}
回报率($a<$b)?-1:1;
}
$tracks=array();
而($row=$result->fetch_assoc()){
$tracks[]=$row;
}
usort($tracks,'normalize');
问题2:这是实现自定义排序的最佳方法吗

这里是我碰壁的地方:

问题3:我不知道如何创建normalize函数来根据需要对名称进行排序。我如何忽略某些字符(,,,!,?),如何用自然等价物(Á->A,É->E等)替换其他字符 我相信,通过忽略某些字符并替换其他字符,我可以实现我想要的排序

问题4:所有这些都有意义吗?我走对了吗

提前谢谢你的建议。 马可

问题2。 这是实现自定义排序的一种很好的方法,那么您需要做的唯一真正的工作就是比较函数

问题3。 使用将字符串转换为其ASCII等效值是值得的。它可以将UTF-8转换为ASCII,并使用Translatit,它将匹配无法直接转换为类似的字符

i、 e.Á->A,Á->e等

转换后,您可以删除不希望使用preg_替换或str_替换进行排序的字符

下面是一个可以使用的比较函数示例

function normalize_string($string) {
    $ascii = iconv("utf-8","ascii//TRANSLIT", $string);
    return str_replace(array('!', "'", '?'), '', $ascii);

    // or

    return preg_replace('/[!\'?]/', '', $ascii);

    // or depending on how much you do want to replace... \W => any "non-word" character

    return preg_replace('/\W/', '', $ascii);
}

function custom_str_cmp($a, $b) {
    return strcmp(normalize_string($a), normalize_string($b));
}

usort($tracks, 'custom_str_cmp');
问题4。 是的。

您可以访问MySQL。然后,你可以忽略任何你不在乎的角色,根据需要去除口音,通常按照你想要的任何一致的方式进行排序

在客户端(即在PHP中而不是在数据库中)执行损坏的排序不会像在数据库中那样快。当您必须在查询中添加
LIMIT
OFFSET
子句时,这种方法也会失败。我不确定自定义排序规则是否适用于
MAX()
类似的函数,但在PHP中执行损坏的排序规则肯定不会正确,除非您要查看整个表,对其排序,然后只获取一个条目

<>所以,我会考虑在数据库之外做排序,作为最后的手段。< /P> 如果不想构建自己的排序规则,另一种选择是在表中构建一个能够正确排序的人工列。您可以在PHPLAND中使用
normalize()
函数(类似Jacob的函数将是合理的起点),并将结果作为一列保存在数据库中,例如,
sortable_title
;然后,
orderbysortable\u title
就可以了。您需要一个
normalize()
PHP函数,该函数生成如下列表(无标点符号,全部小写,重音符号去除,…):

  • 123帕西托斯
  • 非洲
  • 阿罕布拉
  • 阿罗兹
  • 德西里维拉
  • 分贝
因此,一个简单的ASCII测试排序将做正确的事情。当然,在执行插入时必须初始化
sortable_title
,并在更新过程中重新生成,但如果代码被正确封装,这应该是相当直接的


问题4:我想我不同意Jacob的观点,我会说将排序规则移出数据库并没有朝着正确的方向发展。我并不是说你完全偏离了正轨,但是你最好让MySQL处理排序,尽管你可能最终会通过上面概述的
sortable_title
hack之类的方法给它提供一些帮助。

如果我在共享主机上,我可以向MySQL添加我自己的排序规则吗?@Marco:这取决于主机提供商,但我不会可能倾向于“可能不”。如果不能,那么
sortable_title
方法几乎可以完成这项工作。我刚刚完成了两种方法的编程,具有sortable_title的方法速度更快。我添加了一个计时器,mysql解决方案的平均结果是:0.009秒。。。php解决方案:0.12秒。奇怪的是,我缓存了列表(使用ob_start()…方法),缓存速度明显变慢了。。。我猜,在这种特定情况下,打开缓存文件比执行查询慢。。。让你感到奇怪的是,在php中缓存并不总是必要的…@Marco:Nice,你甚至测试了哪个更好!数据库往往会进行大量的比较和排序,因此MySQL的一部分可能会在内存和磁盘上进行大量优化,直至字节布局;一个数量级的性能差异并不让我感到惊讶:数据库擅长大容量数据争用,这就是它们的用途。