2011-03-04 10 views
5

使用MySQL,我選擇西班牙語的歌曲列表,我想排序。以下是查詢返回的名稱列表:在mysql或php中使用utf字符排序?最好的解決方案

  • Decirevilla!
  • 阿罕布拉
  • 123 pasitos
  • 非洲
  • Arroz
  • Decir

排序列表應該是這樣的:

  • 123 pasitos
  • 非洲
  • 阿罕布拉
  • 阿羅茲
  • ¡Decirevilla!
  • Decir

所有的研究,我讀過之後,我已經得出結論,沒有合理的方式來實現這一目標使用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'); 

問題2:這是實現自定義排序的最佳方式嗎?

這裏就是我打牆:

問題3:我不知道如何創建正規化函數名稱相應我的需求進行排序。我如何忽略某些字符(¡,?,',!,¿),以及如何用其自然等價物(Á - > A,É - > E等)替換其他字符。我相信通過忽略某些字符和替換別人,我可以實現排序我是loojing ...

問題4:這一切都有意義嗎?我在正確的道路上嗎?

在此先感謝您的建議。 Marco

回答

1

您可以將add your own collation轉換爲MySQL。然後你可以忽略任何你不關心的字符,根據需要去掉口音,並且通常以任何你想要的方式來排序。

在客戶端(即在PHP而不是在數據庫中)進行破壞性整理不會像在數據庫中那樣快。只要您必須將LIMITOFFSET子句添加到您的查詢中,這種方法也會失敗。我不確定自定義排序規則是否對MAX()類似的函數做了正確的事情,但是在PHP中進行mangled-collat​​ion肯定不會,除非你想把整個表,排序,然後抓取一個條目。

所以,我會考慮在數據庫之外進行排序,作爲最後的手段。

如果您不想構建自己的排序規則,另一個選擇是在表格中構建一個排序正確的人工列。您可以在PHP-land中使用normalize()函數(類似於Jacob's將是合理的起點),並將結果保存在數據庫中,稱爲sortable_title;然後ORDER BY sortable_title會做的伎倆。你想要的是生產像這樣的列表(沒有標點符號,全部小寫,口音剝離,...)一normalize() PHP函數:

  • 123 pasitos
  • 非洲
  • 阿罕布拉
  • arroz
  • decirevilla
  • decir

這樣一個簡單CII-betical排序會做正確的事情。當然,在執行INSERT時,您必須初始化sortable_title,並在UPDATE期間重新生成它,但如果您的代碼已正確封裝,則應該相當直接。

問題4:我想我會不同意雅各布的觀點,並且表示通過將排序規則移出數據庫,你不會走向正確的方向。我並不是說你完全偏離了軌道,但你最好讓MySQL處理排序,即使你最終可能會給它提供一些幫助,比如上面列出的sortable_title黑客。

+0

如果我在共享主機上,我可以將自己的排序規則添加到MySQL嗎? – Marco 2011-03-04 23:05:46

+0

@Marco:這取決於託管服務提供商,但我可能傾向於「可能不是」。如果你不能,那麼'sortable_title'方法也能完成工作。 – 2011-03-05 04:27:26

+1

我剛剛完成了兩種編程方法的編程,而sortable_title編寫的方法更快,速度更快。我已經添加了一個計時器和mysql解決方案的平均結果:0.009秒... php解決方案:0.12秒。奇怪的是我已經緩存了列表(使用ob_start()..方法),並且緩存明顯更慢......我想,在這種特定情況下,打開緩存文件比執行查詢要慢。 ..讓你想知道,在PHP緩存並不總是必要的... – Marco 2011-03-05 17:39:50

0

問題2 這是一種實現自定義排序的好方法,那麼唯一真正的工作就是在比較函數上。

問題3 可能值得使用iconv將字符串轉換爲ASCII碼。它可以將UTF-8轉換爲ASCII並使用translit,它將匹配不能直接轉換爲看起來像它的東西的字符。

即 - > A,E - > E等。

一旦它轉換完成,您就可以使用preg_replace或str_replace刪除不想排序的字符。

下面是您可以使用的比較函數的示例。

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. 是的。

相關問題