HSP | 日本語等も一文字として strlen, strmid

HSP | 日本語等も一文字として strlen, strmid

タイトルの通りです。
HSP って、strlen や strmid は、日本語等は二文字 (というより本当はバイト単位) なんですよね…。
…もしかして、HSP しか使っていない人にとっては、日本語等が 2 文字扱いになるのに違和感を感じないかもしれませんが、他のプログラミング言語だと結構日本語が一文字扱いなのですよ (^^;
使い方にもよってですが、実際そのほうが使いやすかったり… (汗
…というわけで、HSP でも日本語等を一文字扱いで、とりあえず strlen と strmid を対応しようと思います!!
(他の文字列関係の命令・関数は文字数関係ないか、関係していても、基本的にプログラマが数値を指定するようなものではない (instr など、ループで回すだけ) ので、ここでは省略します。

コード

/**
 * メイン
 */

// 文字列の長さ
mes strlen_("aiueo")
mes strlen_("あいうえお")
mes strlen_("aいuえo")
mes

// 文字列の一部を取り出す
mes strmid_("aいuえo", 2, 2)
mes

mes strmid_("aいuえo", -1, 1)
mes strmid_("aいuえo", -2, 2)
mes strmid_("aいuえo", -3, 1)
mes

mes strmid_("aいuえo", 0, -1)
mes strmid_("aいuえo", 2, -1)
mes strmid_("aいuえo", 3, -1)
mes strmid_("aいuえo", -3, -1)
mes

stop

/**
 * 文字列の長さを調べる (日本語等も一文字)
 */
#defcfunc strlen_ str s

l = 0

sdim buf, strlen(s) * 2 + 2
cnvstow buf, s

repeat
if ( 0x0000 == wpeek(buf, cnt * 2) ) : break
l++
loop

return l

/**
 * 文字列の一部を取り出す (日本語等も一文字)
 * 
 * index がマイナスのときの挙動変更 (後ろからのインデックス)
 * len   がマイナスのときの挙動変更 (後ろからのインデックス)
 */
#defcfunc strmid_ str s, int index, int len

sdim buf, strlen(s) * 2 + 2
cnvstow buf, s

// インデックスを修正
if ( index >= 0 ) {
i = 0
repeat index
if ( 0x0000 == wpeek(buf, cnt * 2) ) : break
i++
loop
} else {
i = 0
repeat
if ( 0x0000 == wpeek(buf, cnt * 2) ) : break
i++
loop
i = limit(i + index, 0, i)
}

// 長さを修正
if ( len >= 0 ) {
l = 0
repeat len, i
if ( 0x0000 == wpeek(buf, cnt * 2) ) : break
l++
loop
} else {
l = 0
repeat , i
if ( 0x0000 == wpeek(buf, cnt * 2) ) : break
l++
loop
l = limit(l + len, 0, l)
}

// 切り出し
memcpy buf, buf, l * 2, 0, i * 2
wpoke buf, l * 2, 0x0000

return cnvwtos(buf)

使い方

基本的に元の strlen, strmid と使い方は同じです。
ただし、strmid は一部仕様を変更しています。

1.文字列を直接引数にとれるように

HSP 標準関数の strmid では文字列型「変数」を引数に渡すことを強制していますが、ここで作成したものに関しては、内部的にバッファを作ってそこで捜査していますし、そもそも元の変数の内容を変更するわけじゃないから、そもそも変数で渡す必要ないような…? HSP での実装どうなってるんでしょう (^^; (HSP のコード読めば分かるのですけどね

2.インデックス、長さにマイナス値の指定

インデックス・長さがマイナスのときの挙動を、PHP の substr ライクにしてみました!! (^^
…ただ、引数の省略の機能は省いています… (^^;
HSP で関数を #define してやればデフォルト引数指定できますが、数値しか渡せないとなると、わりと厄介なんですよね…。

コードの説明

昔の HSP にはなかったような? 気がするのですけど、標準命令・関数に、文字列を Unicode に変換するものがあったので、それを用いて数えます!
… Unicode でも、文字よってバイト数が違うものがありますが、HSP のその変換する命令・関数のヘルプを見てみると、「外部DLL、 COMオブジェクトへのデータ変換などで使用することができます」と書いてあるあたり、Windows の API でよく使用されるワイド文字で、2 バイト固定という認識でおそらく大丈夫…ですよね?? たぶん…。
というわけで、あとは、一文字 2 バイトという過程でごにょごにょしてます (説明がテキトー (^^;
(詳しくはソースコード参照
Unicode 文字列に変換するさいにバッファのサイズが足りないとマズいのですが、最低限、通常の strlen でえられる長さの倍あれば足りるでしょう。 (ヌル文字も考慮してプラス 2 バイト)

雑談

バイト数で取得していると、基本的に全角文字が 2 文字あつかいになって嬉しい、という意見もあるかもしれないですが、等幅じゃないとその数値役に立たないですし、そもそも半角カタカナが 2 バイトという罠があったりして、あまり実用的でないような… (^^;
やっぱり、HSP 標準の strlen は文字列の長さというより単なるバイト数として使用すべきですね…。
では、またいつかお会いしましょう! (^^
ノシ