nptclのブログ

Common Lisp処理系nptの開発メモです。https://github.com/nptcl/npt

C言語でEast Asian Widthを調べる

1. はじめに

C言語でEast Asian Widthを調べるコードを作りました。
作ったといってもnptのソースから抜き出しただけですが。

配布はここ。

https://github.com/nptcl/hypd/tree/main/develop/eastasian

ある機能がnpt内だけで使えるというのは個人的に不便だったので、 いくつかの機能を分離させて登録することにしました。

East Asian Widthとは、全角/半角のUnicode版です。
」という文字は全角で、「A」という文字は半角です。
しかし「」という文字は全角になります。
ブラウザによっては見づらいかもしれません。

ファイルは下記の通り。

  • eastasian.c
  • eastasian.h
  • unicode.h

このうちunicode.hはダミーファイルの位置づけであり、 あとでUnicodeを操作する本物のファイルをどこかに登録する予定です。
ダミーの内容はtypedef int32_t unicode;だけです。

2. 使い方

使い方は簡単です。

unsinged x;
x = eastasian_width('A');

A」は半角なので、xには1が入ります

x = eastasian_width(0x3042);  /* あ */

」は全角なので、x2が入ります。

East Asian Widthというのは、全角と半角だけではなく、 種類がいくつかあります。
いったい何の種類なのかを調べたいときはeastasian_symbol関数を使用します。

enum EastAsianType y;
y = eastasian_symbol('A');

A」はNaという型なので、yにはEastAsian_Naが入ります。

y = eastasian_symbol(0x3042);  /* あ */

」はWという型なので、yにはEastAsian_Wが入ります。

返却される種類は下記の通り。

EastAsian_error
EastAsian_N
EastAsian_A
EastAsian_H
EastAsian_W
EastAsian_F
EastAsian_Na

このうち、どの種類が全角なのか、あるいは半角なのかは、 いろんな都合で違っているようです。
一応変更できるようにしています。
初期値に戻すinit_eastasian関数を見てみましょう。

void init_eastasian(void)
{
    EastAsianSymbol[EastAsian_error] = 0;
    EastAsianSymbol[EastAsian_N] = 1;
    EastAsianSymbol[EastAsian_A] = 2;
    EastAsianSymbol[EastAsian_H] = 1;
    EastAsianSymbol[EastAsian_W] = 2;
    EastAsianSymbol[EastAsian_F] = 2;
    EastAsianSymbol[EastAsian_Na] = 1;
}

こんな感じで自由に変えてください。
EastAsianSymbolグローバル変数の配列です。
eastasian_width関数はこの変数を見ます。

スレッド使ってるからグローバル変数なんて使いたくないやって方は、 eastasian_symbol関数で種類を取って自分で判定してください。

3. 技術的なこと

East Asian Widthの値は、Unicodeの本家でファイルとして配布されています。
具体的にはここです。

http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt

このファイルを読み込み、C言語のソースを直接出力しました。
それをやっているのがmake/hypd.eastasian.lispです。
Common Lispで作成してあります。

ファイルの内容はまあまあ大きいので、 調べたい文字を頭から順に探索するわけにはいきません。
かといってUnicodeの全文字を配列にするのも メモリがもったいないなという気がしたので、 C言語のソースにはソートした内容を出力し、 それを二分探索して型を調べています。

二分探索なのでまあまあ早いのですが、 最速ではないということだけは覚えておいてください。
ちなみに文字コード0x00から0x80までは配列に格納されているので 調べるのは一瞬です。