nptclのブログ

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

C言語でUTF-8などを読む

1. はじめに

C言語で、UTF-8などを読み込むコードを作成しました。
これもnptの抜き出しです。

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

たぶん私だけだと思いますが、 UTF-8の読み込みは本当によく使います。
どれだけ同じようなものを作ったことか。
必要になるたびにnptのコードをコピーして改造して使っていました。
もうそんなのやめたいと思って作ったわけです。

今回のコードができることは、次の二点です。

  • ひとつの文字だけ読む
  • ひとつの文字だけ書く

主な内容はこれだけです。
しかもコードをコピーしやすくしました。
これで遠慮なくどこにでも貼りつけられる。

2. 使う

例で使用する変数宣言から。

int x;
unicode c;
struct state_utf8 decode;

使う前に初期化しましょう。

init_utf8(&decode);

ひとつの文字を読み込んでみます。

x = decode_utf8(&decode, 'A', &c); /* x=1, c='A' */

文字が読めたら返却値x1です。
同時に変数cに結果の文字'A'が格納されます。

続けて読み込みできます。

x = decode_utf8(&decode, 'B', &c); /* x=1, c='B' */

ちょっと変な文字を読み込んでみましょう。

x = decode_utf8(&decode, 0xF0, &c);  /* x=0 */

返却値x0のときは、続けて入力が必要です。

x = decode_utf8(&decode, 0x9F, &c);  /* x=0 */
x = decode_utf8(&decode, 0x80, &c);  /* x=0 */
x = decode_utf8(&decode, 0x80, &c);  /* x=1, c=0x01F000 */

返却値x1になると、読み込んだ文字をcに格納します。
今の場合は、UTF-8のコードF0 9F 80 80で、 U+1F000という文字ができあがります。
ちなみにこの文字は麻雀牌の🀀です。

次のような場合を考えます。

x = decode_utf8(&decode, 0xF0, &c);  /* x=0 */
x = decode_utf8(&decode, 0x7F, &c);  /* x=-1, ERROR */

2つめの入力0x7Fは正しくないため、 返却値xはエラーを示す-1になります。
こうなると、以降の操作は全てエラーになります。

x = decode_utf8(&decode, 'A', &c);  /* x=-1, ERROR */

元に戻したいときは初期化しましょう。

init_utf8(&decode);
x = decode_utf8(&decode, 'A', &c);  /* x=1, c='A' */

ついでに書き込みも説明します。
まずは変数宣言から。

int x, y;
uint8_t array[4];

配列arrayには、UTF-8のコードが格納されます。
4つもあれば十分です。

それではU+1F000という文字のUTF-8を求めましょう。

x = encode_utf8(0x1F000, array, &y);

うまくいったときは、返却値x0になります。
変数yには、配列arrayにいくつ書き込んだかを格納します。
今の場合は4byteなので、y=4です。
コードは下記のようになります。

array[0] = 0xF0
array[1] = 0x9F
array[2] = 0x80
array[3] = 0x80

これでUTF-8の入出力はできるようになりました。