Data.CharのGeneralCategoryにSurrogateという文字があることに気付いて対応しているのかなと思い、実験してみた。環境はScientific Linux 6.0+GHC7.0.3。
import Data.Char (GeneralCategory(..), generalCategory)
main = do
let c = '\x20213'
putChar c
putStrLn $ show c
putStrLn $ show $ generalCategory c
putStrLn $ if generalCategory c == OtherLetter then "yes" else "no"
putStrLn $ if generalCategory c == Surrogate then "yes" else "no"Mac OS X 10.6.8のターミナルからリモートログインして実行したときの結果。ターミナルではCourierフォントを使っていましたが文字化けせずに表示されました。
*Main> main 𠈓'\131603' OtherLetter yes no
予想外だったのはgeneralCategoryの結果がSurrogateではなくOtherLetterだったこと。調べてみるとこれは単に私がUnicodeをよく知らないだけでした(以下の調査結果参照)。
ghc-7.0.3-src.tar.bz2のlibraries/Base/Data/Char.hsを見てみたところ、以下のような定義になっていた。
-- | The Unicode general category of the character. generalCategory :: Char -> GeneralCategory #if defined(__GLASGOW_HASKELL__) || defined(__NHC__) generalCategory c = toEnum $ fromIntegral $ wgencat $ fromIntegral $ ord c #endif #ifdef __HUGS__ generalCategory c = toEnum (primUniGenCat c) #endifwgencatは79行目に定義されていました。
#ifdef __NHC__ import Prelude import Prelude(Char,String) import Char import Ix import NHC.FFI (CInt) foreign import ccall unsafe "WCsubst.h u_gencat" wgencat :: CInt -> CInt #endif
u_gencatはbase/cbits/WCsubst.cで定義されていました。
int u_gencat(int c)
{
return getrule(allchars,NUM_BLOCKS,c)->catnumber;
}getruleの定義はこちら。どうやらallcharsという配列をバイナリサーチで探すようだ。
static const struct _convrule_ *getrule(
const struct _charblock_ *blocks,
int numblocks,
int unichar)
{
struct _charblock_ key={unichar,1,(void *)0};
struct _charblock_ *cb=bsearch(&key,blocks,numblocks,sizeof(key),blkcmp);
if(cb==(void *)0) return &nullrule;
return cb->rule;
}目で探してみるとこちら。
{131072, 42711, &rule45},
{194560, 542, &rule45},rule45を見てみるとLO、つまりOtherLetterです。
static const struct _convrule_ rule45={GENCAT_LO, NUMCAT_LO, 0, 0, 0, 0};一方、Surrogateを探すとこちらにありました。
static const struct _convrule_ rule157={GENCAT_CS, NUMCAT_CS, 0, 0, 0, 0};使っている箇所は以下の3箇所でした。
{55296, 896, &rule157},
{56192, 128, &rule157},
{56320, 1024, &rule157},
{57344, 6400, &rule158},http://www.unicode.org/Public/zipped/6.0.0/UCD.zipのUnicodeData.txtを見て謎が解決しました。General CategoryがCs (Surrogate)なのはサロゲートペアの片割れのコードということのようです。
…(略)… D800;;Cs;0;L;;;;;N;;;;; DB7F; ;Cs;0;L;;;;;N;;;;; DB80; ;Cs;0;L;;;;;N;;;;; DBFF; ;Cs;0;L;;;;;N;;;;; DC00; ;Cs;0;L;;;;;N;;;;; DFFF; ;Cs;0;L;;;;;N;;;;; …(略)… 20000; ;Lo;0;L;;;;;N;;;;; 2A6D6; ;Lo;0;L;;;;;N;;;;; …(略)…
0 件のコメント:
コメントを投稿