#author("2018-06-23T02:00:56+09:00","","")
[[モートン番号テーブル化 / 八分木]]
#author("2018-06-23T02:01:47+09:00","","")

----
#contents
----
HSP でのシフトジスに関するページ~

このページでは HSP によるシフトジスにまつわる情報をまとめています(主に HSP バージョン3系統です)。~
Windows 版の HSP が標準的に扱う文字の種類はシフトジスといって、アルファベットや日本語のひらがな、カタカナ、漢字など様々な文字種を扱う事が出来ます。~
ただしシフトジスにも扱えない文字が多くあるため、更に多くの文字種を扱いたい場合にはユニコードの使用も検討してください。~

*シフトジスの判定 [#o9b17c20]

シフトジスは1文字を表すために1バイト〜2バイトを必要とするマルチバイト文字です。1バイト取り出したからといってそれが一文字とは限りません。
そのため自分で一文字ずつ扱いたい場合には、その一文字が1バイトか2バイトか判断し処理していく必要があります。~

**シフトジスの文字コードの範囲表 [#k9f2d8a4]

ascii は半角のアルファベットや記号や制御文字を扱う文字コードで、常に1文字1バイトに収まります。~
shift_jis は ascii を含めて日本語なども扱えるようにした文字コードで、ascii を含んでいるため1文字で1〜2バイトと変動します、ascii 以外の文字を使う場合に2バイト必要になります。~

以下に文字コードの値の範囲を表にして見ました。
#ref(sjis_range.png)
ピンクがアスキーの範囲、~
ライトブルーが2バイト文字のリードバイト、~
イエローがそのトレイルバイト。

シフトジスは1文字で2バイト必要な時、初めのバイトをリードバイト、次のバイトをトレイルバイトと言い、この2バイトのセットで1文字を表す。

**getstr を使って判定する [#t0c46c94]

とりあえず手っ取り早くやるには、getstr の内部に判定処理が入ってるので、それを間接的に利用し一文字ずつ取得、その取得結果から判定する
	txt = "abcあいうxyz"
	i = 0
	repeat
		getstr get, txt, i,, 1	; 一文字取得
		if strsize = 0	:break
		i += strsize
		mes get + "(" + strlen(get) + ")"
	loop

**シフトジスの文字コードの範囲を調べて判定する [#pdf7592b]

文字列中に混在した文字を自分で判定して区別したい場合は、文字列を1バイトずつ調べて、その数値がシフトジスの文字コードの範囲内かどうかを判定し、判定結果からそれぞれ相応しい処理に分ける。~
文字コードの判定は上の文字コード表の範囲かどうかを if 命令で調べている。~
以下はリードバイトのみを判定する処理。

 // 判定用マクロ、パラメータに指定した文字コードがシフトジスのリードバイトか調べる
 // シフトジスのリードバイト なら 1 が返る、違えば 0 が返る
 #define global ctype IS_SJIS(%1) ( ( $81 <= (%1) ) & ( (%1) <= $9f ) | ( $e0 <= (%1) ) & ( (%1) <= $fc ) )
 
 	txt = "abcあいうxyz"
 
 	repeat strlen(txt)
 		code = peek(txt, cnt)
 		if IS_SJIS(code) {
 			mes strmid(txt, cnt, 2)
 			pos GINFO_CX + GINFO_MESX + 8, 0
 			continue cnt + 2
 		} else {
 			mes strmid(txt, cnt, 1)
 			pos GINFO_CX + GINFO_MESX + 8, 0
 		}
 	loop

**シフトジスの範囲判定処理の効率化 [#na3814d4]

上のシフトジス判定処理の計算量を減らして効率化する。~
このサイト:http://www5d.biglobe.ne.jp/~noocyte/Programming/CharCode.html#IsSjisLeadAndTrail~
と、その中にある「~
 ┌ここで見つけた巧妙な判定方法.~
 ↓(上の方法に比べ,条件分岐が2〜4回から1回に減るので少し高速化できそう.)~
 初級C言語Q&A(15)【シフトJISの1バイト目の判定】~
」~
の部分に張ってあるリンク先:http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html#Q4~
の内容を参考に判定方法を HSP 用に書き換えて見たもの。~
上の項目と同様に、以下はリードバイトのみを判定する。
 // 判定用マクロ
 #define ctype IS_SJIS(%1) ( (((%1) ^ $20) - $A1 & $FF) < $3C )	// %1 が シフトジスのリードバイトか
 
 	text = "あabいcdうeえfおg"
 
 	repeat strlen(text)
 		c = peek(text, cnt)
 		if IS_SJIS(c) {
 			mes strmid(text, cnt, 2) + " 1"
 			continue cnt + 2
 		} else {
 			mes strmid(text, cnt, 1) + "  0"
 		}
 	loop
これを書いてから思い出したが、昔どこかで HSP での似た様な書き方を見た様な気がしてきたけど、どこにあるのか、探しても見つからなかった。

*その他 [#q3567379]

シフトジスとは直接関係無いが小ネタ的なもの。

**無作為に選んだ文字列中の場所からその行の先頭を見つける [#s9d1df85]

HSP での改行は CRLF で数値に直すと CR=0x0d(13), LF=0x0a(10)ですが、上の範囲表の画像を見ると分かるとおり、どちらもアスキー固有の範囲内のみに収まっている(シフトジスの範囲に掛かっていない)ので 1 byte ずつ後ろ向きに遡って調べても判別することができます。
 	// 対象文字列
 	text = "abcdefg\nあいうえお\nhijklmn\nかきくけこ\nopqrstu\nさしすせそ\nvwxyz\nたちつてと\n0123456789\nなにぬねの"
 	mes text
 	objsize 150, 25
 	button "ランダム位置から行頭取得", *BTN
 	cy = GINFO_CY
 	randomize
 	stop
 
 *BTN
 	len = strlen(text)	; 全体文字列長
 	random = rnd(len)	; 文字列長以内の乱数取得
 	index = random		; 乱数を開始インデックスに
 	// 遡って行頭を見つける
 	repeat
 		// 改行なら次の文字に(手抜き)
 		if peek(text, index) = $0a	:index ++	:break
 		if peek(text, index) = $0d	:index ++	:continue
 		if index = 0	:break	; 0 文字目に来たら抜ける
 		index --		; 逆向きに探す
 	loop
 	// 結果表示
 	getstr get, text, index		; 見つけた行頭から1行分取得
 	result = strf("行頭位置:%d / 乱数:%d / 全体の文字列長:%d\n%s", index, random, len, get)
 	color 255, 255, 255	:boxf 0, cy, GINFO_WINX, GINFO_WINY
 	color	:pos 0, cy	:mes result