PHP・MySQL~意外と面倒、マルチバイト文字列の並べ替え
MySQLでデータ抽出する際、あるカラムをキーに並べ替えをしたい時は、【昇順】(数値、文字コードの小さいもん順)select * from テーブル名 order by カラム名 ASC【降順】(数値、文字コードの大きいもん順)select * from テーブル名 order by カラム名 DESCでも、これって日本語を含むマルチバイト文字列には有効ではないみたい。(2バイト以上使うマルチバイト文字列の1バイト目だけを見て処理してしまうっぽい)。ならばPHPに取り込んでからなんとかなるかな?…と思ったが、意外にマルチバイトを「並べ替え」る関数はなし。usortというユーザ定義規則で並べ替える関数、mb_convert_encodingという、文字コードを変換する関数、そしてordという1バイト文字の文字コードを返す関数、これらを併用してユーザ定義関数を作るしかないよう。まず、マルチバイト対応の文字コードを返す関数を定義。function uniord($u) { $k = mb_convert_encoding($u, 'UCS-2LE', 'UTF-8'); $k1 = ord(substr($k, 0, 1)); $k2 = ord(substr($k, 1, 1)); return $k2 * 256 + $k1;}※出典:PHP Manual: ord の "v0rbiz at yahoo dot com" 氏によるコメント。次にマルチバイト対応の比較関数定義#==== $a が前だと-1、後ろだと1、同じだと0を返すfunction mbcmp($a,$b){ #== 短い方の文字の長さを取得し、短い方が前と仮判定 #- $a の方が短い場合 if (strlen($a) < strlen($b)) { $len = strlen($a); $cmp = -1; #- $a の方が長い場合 } else if (strlen($a) > strlen($b)) { $len = strlen($b); $cmp = 1; #- 同じ長さ } else { $len = strlen($a); $cmp = 0; } #== 変数定義 $i = 0; #- チェック位置(最初の文字が0) $flg = true; #- チェック継続フラグ(falseになると判定終了) #== チェック while ($flg !== false) { #- i-1文字目が同じ if (substr($a,$i,1) == substr($b,$i,1)) { #- チェック位置を次に $i++; #- 短い方の最後まで到達→短い方=長い方の前部→短い方が前 if ($i >= $len) { $flg = false; } #- i-1文字目が違う } else { #- $a の($i-1)文字目の文字コード $code_a = uniord(substr($a,$i,1)); #- $b の($i-1)文字目の文字コード $code_b = uniord(substr($b,$i,1)); #- $a の文字コードの方が小さい場合→$aが前 if ($code_a < $code_b) { $cmp = -1; #- $b の文字コードの方が小さい場合→$bが前 } else if ($code_a > $code_b) { $cmp = 1; } $flg = false; } } return $cmp;}その上で、uasort($array,'mbcmp');とすれば、$array 配列の中身が文字コードの小さい順に並べ替えされる。参考:メモ:PHP関係(個人メモサイト)