ソラマメブログ

2009年04月29日

LSL:日本語文字列をバイト数で長さ制限

LOSTのSIM(過去記事は→こちら)に行くのに
ドラマの中でみんながもってるようなリュックを作ってます。

LSL:日本語文字列をバイト数で長さ制限

まだスカルプ作っておおまかな形作っただけやけどねー
こういう私物は主に自分で作って自分で使うみたいな遊び方なんですが、
たまにお友達にあげることもあるので、色ぐらいはダイアログで変更できるようにしています。

で、いつもあんまり日本語のこと考えずに作ってたのですが、
この間発見したこちらのページで感激しました。

Second Life 見たこと・聞いたこと [LSL] 文字列のバイト数を調べたい - llDialog

目からうろこです!!

ぼろっって大きなうろこが落ちてきました。

ってことで、日本語を含む文字列のバイト数を調べたり、バイト数で長さを制限したりに挑戦してみました。


* * *


処理の基本的なアイディアに関しては、 参照元の記事をご覧下さい。

あえてポイントをまとめるとすばらしい点が2点もあります。

(1)UTF-8の文字のコードを取得する方法
(2)UTF-8の文字によってバイト長が変化するのをカウントする方法

この記事では以下のように解決しておられました。

(1)UTF-8の文字のコードを取得する方法

LSLの中には、charCodeAt()みたいな文字のコードを取得する関数とかないんですよね。
コードがわからないと日本語処理できないと思い込んでたのですが、

「URLエンコードを使えばいいやん」


というアイディアです。
まったく気がつきませんでした。
英数字のコードは取得できませんが、
目的は日本語部分のコードを取得することですから実用上問題ありません。
すばらしいです!!


(2)UTF-8の文字によってバイト長が変化するのをカウントする方法

元記事にも詳しく説明がありますが、UTF-8は文字によって1バイトから4バイトまで変化します。
普通なら、1文字ずつ長さを調べて足し算していくことを考えると思うのですが、
ここで、またすばらしい提案が!

「'%'をカウントすればいいのよ」

うう・・そんなことまったくきがつかへんかったー

URLエンコードすると、こんな感じになります

文字URLエンコード結果説明
AA英数字はもとのまま
+%2B%が1つ
×%C3%97%が2つ
%E3%81%82%が3つ

%の数と、文字のバイト長が同じってことなんですー
コペルニクス的な発想ですよね!


これらすばらしいアイディアをいただいて、
無謀にもちょっとだけ改造してみました。


//----------------------------------------------------
//  文字のバイト数
//  参考:http://snumaw.blogspot.com/2009/01/lsl-lldialog.html
//----------------------------------------------------
integer strlenB(string str){
    string  esc = llEscapeURL(str);
    string  wk  = llDumpList2String(llParseString2List(esc,["%"],[]),"");
    integer cnt = llStringLength(esc) - llStringLength(wk);
    return llStringLength(esc) - cnt * 2;
}


if文をなくしてみたのですが、いまのところうまく動いてる気がします。



■バイト数で長さを制限

さらにこのアイディアを使ってバイト数で長さを制限に挑戦しようとしたのですが・・・
リストを使った処理が閃かなくて・・・
URLエンコードのアイディアだけいただいてごりごり書いてみました。
関数の名前が、適当なんですけど・・・(substrじゃない気もする)

//----------------------------------------------------
//  バイトで指定した長さ以下の文字列
//  参考:http://snumaw.blogspot.com/2009/01/lsl-lldialog.html
//----------------------------------------------------
string substrB(string str, integer lenB) {
    string  out = "";
    integer cnt = 0;
    integer i   = 0;
    integer n   = llStringLength(str);
    
    for (;i < n && cnt < lenB; i++) {
        string wk  = llGetSubString(str, i, i);
        string esc = llEscapeURL(wk);
        if (llGetSubString(esc,0,0) == "%") {
            integer cd = (integer)("0x" + llGetSubString(esc,1,2)); 
            integer cc = ((cd & 0x80) == 0)
                       + ((cd & 0xE0) == 0xC0) * 2
                       + ((cd & 0xF0) == 0xE0) * 3
                       + ((cd & 0xF8) == 0xF0) * 4;
            cnt += cc;
        }
        else {
            cnt ++;
        }
        if (cnt <= lenB) out += wk;
    }
    return out;
}




■タブ記号の扱い

上記2つの関数内では、文字列を一旦URLエンコードします。
LSLのllEscapeURL()関数は、タブ記号を内部的に4つのスペースに変換してしまうようなので、
出力もタブ記号に関しては4バイトの取扱になります。
この処理を入れようかどうか迷ったのですが、Dialog関数の文字制限も、タブを4つのスペースとして判断しているっぽいのでそのままにしました。

ちなみに改行は1バイトになります。


なにかへんなトコあったら容赦なくご指摘ください^^

最後になりましたが、
すばらしいアイディアを公開していただいたWhitfieldさんに感謝です♪



※出番がないのでもう1枚LOSTの写真を貼っておきますねー
本文と関係なくてごめんねー

LSL:日本語文字列をバイト数で長さ制限



同じカテゴリー(Tips)の記事画像
プリムスカートの簡単な作り方のヒミツ。初めてわかりました^^
球面の内側にテクスチャを貼るときの覚書です^^
スナップショットをレンズぼかしで加工してみました^^
LSLのカラーに変換するツールを作ってみました^^
ブラウザからインワールドの検索を使ってます^^
ソラマメ・アルバムのカスタマイズしてみました^^
同じカテゴリー(Tips)の記事
 プリムスカートの簡単な作り方のヒミツ。初めてわかりました^^ (2009-07-11 14:57)
 球面の内側にテクスチャを貼るときの覚書です^^ (2009-06-27 07:28)
 スナップショットをレンズぼかしで加工してみました^^ (2008-10-06 04:14)
 LSLのカラーに変換するツールを作ってみました^^ (2008-10-02 21:15)
 ブラウザからインワールドの検索を使ってます^^ (2008-09-02 17:39)
 ソラマメ・アルバムのカスタマイズしてみました^^ (2008-07-24 23:56)

Posted by jinko at 12:06│Comments(2)Tips
この記事へのコメント
ほめすぎです・・・(^^;
jinko さんのバイト数チェックのほうが洗練されているので、元の記事のほうにも追記でこの記事を紹介させていただきました。
ありがとうございます~。
Posted by Whitfield-In-WorldWhitfield-In-World at 2009年05月01日 20:25
Whitfield-In-World さん^^

こちらまでお越しいただいて感激です♪

うまく伝えられないですが、ホントすばらしいアイディアなので
いくら賞賛しても足りないくらいです^^

Whitfield-In-World さんの、いつもためになるブログ。
これからも楽しみにしています^^

こちらこそありがとうございましたー
Posted by jinkojinko at 2009年05月02日 06:23
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。