読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

gforthで日本語文字列(UTF-8)を扱う

マニュアルを見ながら日本語をいろいろ操作してみたメモ。

Forthの文字列はアドレス バイト数の組なので、s" うたちゃん"などでUTF-8を読み込むと、1byteずつのデータとして認識される。

s" うたちゃん" .s <2> 13793104 15  ok   ( UTF-8の日本語なので3バイトずつ5文字の15バイト )
type うたちゃん ok                      ( typeは素直に出力するので表示はできる          )

これをUTF-8としていろいろ操作してみる。このUTF-8で構成された文字列を今回はxcharと呼ぶ。

gforthでは(Forth 200Xでは?)UTF-81文字を1セル分、31bitまでのxcとして扱うワードがいろいろあるみたいだ。

1文字表示する

まずxcharからxcを1文字取り出す。xc@+ ( xchar-addr1 -- xchar-addr2 xc )で、渡されたxcharアドレスからxcを1文字取り出し、さらにアドレスを次の文字に進められる。

さらにxemit ( xc -- )で1文字表示する。

s" うたちゃん"  ok   ( xchar-addr bytes )
drop  ok             ( xchar-addr )
xc@+ xemit う ok
xc@+ xemit た ok
xc@+ xemit ち ok
xc@+ xemit ゃ ok
xc@+ xemit ん ok

1文字切り落とす

xcharを前から1文字切り落とすには+x/string ( xchar-addr1 bytes1 -- xchar-addr2 bytes2 )を使う。xc1個分、アドレスを進ませ、バイト数を減らす。

s" うたちゃん" .s <2> 13793200 15  ok
+x/string .s      <2> 13793203 12  ok
type たちゃん ok

同じようにx\string-を使えば、後ろから切り落とすことができる。アドレスはそのままで、xcharの最後のxc1個分、バイト数を減らす。

s" うたちゃん"  ok
x\string- .s <2> 13793328 12  ok
type うたちゃ ok

UTF-8文字列の文字数を測る

: xchar-len  ( addr u -- n )
   0  BEGIN
     over 0>    ( バイト数uがまだ残ってるか )
   WHILE
     1 +        ( 1文字カウント     )
     -rot       ( n addr u          )
     +x/string  ( 前から1文字カット )
     rot        ( addr u n          ) 
   REPEAT ;

1行にすると : xchar-len ( addr u -- n ) 0 BEGIN over 0> WHILE 1 + -rot +x/string rot REPEAT ;

これでUTF-8の文字数を数えることができる。

s" うたちゃん" xchar-len . 5  ok
s" うた!"     xchar-len . 3  ok
s" uta!"     xchar-len . 4  ok  ( "!"だけ3バイト文字 )

ほか

xchar-addrを受け取ってxc1個分アドレスを前後させるxchar+xchar-バッファオーバーフローに対応したxc書き込みのxc!+?などがある。

エンコーディングUTF-8に限定してしまえば割と文字列の扱いも難しくない……かな?

Forthを書こう

というわけで少しずつ書いているので、得た知見を書き貯めておきたい。

広告を非表示にする