物事の順位付けをするとき、松竹梅という雅な表現がよく使われる。自分もよく使う。
コンピュータにとってもそうなのだろうか?そう考えた私は実際にソートしてみることにした。
% echo $LANG ja_JP.UTF-8 % sort --version sort (GNU coreutils) 9.3 Copyright (C) 2023 Free Software Foundation, Inc. ライセンス GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. 作者 Mike Haertel および Paul Eggert。 % echo -n "竹梅松" | sed -ne 's/./\0\n/gp' | sort 松 竹 梅
本当に松竹梅になった。
コードポイントやUTF-8バイト列を見る
ところで、本当にデータがこの通りになっているのだろうか。検証のために、エンコーディングを試すコードを書いてみた。
#!/usr/bin/env -S scala-cli shebang //> using scala 3.3.0 //> using dep "commons-codec:commons-codec:1.16.0" import org.apache.commons.codec.binary.Hex import collection.JavaConverters.{*, given} def byte2ubyte(b: Byte): Int = b & 0xff for (s <- args) { val cp = s.codePoints .iterator() .asScala .map(i => BigInt(i.toInt)) .map(_.toByteArray) .map(Hex.encodeHexString) .map(u => s"U+$u") .mkString(" ") val ss = s.getBytes().map(byte2ubyte).mkString(" ") val hex = Hex.encodeHexString(s.getBytes()) println(s"$s -> $ss ($hex in hex array, $cp in Unicode codepoint)") }
できた。
松竹梅のコードポイントとUTF-8表現を検査してみる。
% scala-cli show-utf8.scala.sc -- 松 竹 梅 Compiling project (Scala 3.3.0, JVM) Warning: there was 1 deprecation warning; re-run with -deprecation for details Compiled project (Scala 3.3.0, JVM) 松 -> 230 157 190 (e69dbe in hex array, U+677e in Unicode codepoint) 竹 -> 231 171 185 (e7abb9 in hex array, U+7af9 in Unicode codepoint) 梅 -> 230 162 133 (e6a285 in hex array, U+6885 in Unicode codepoint)
バイト列でもコードポイントでも、ぜんぜん竹のほうが大きいことがわかった。最下位バイトはちょうど降順になっているけれど、sort
は普通は昇順で並べるので関係ないはず。
sortの実装
sortは、strcoll()
を使って文字列を比較しているらしい。そしてそれはLC_COLLATE="ja_JP.UTF-8"
を参照しているようだ。
ちなみにScalaでソートするとコードポイント順になる:
scala> "竹梅松".sorted val res1: String = 松梅竹
自分のC読解力だとどこで差異が発生しているかわからなかった。暇な人はチャレンジしてみてください。
結論
- 松竹梅はソートすると本当は松竹梅ではないが、
sort
すると松竹梅になる