〜 テキスト 〜
全角半角文字の判別

Windows版のHSP標準文字コードはシフトJISですので、使用文字により半角全角が混合してしまいます。
HSPに標準の文字列操作命令が幾つも用意されていますが、
パラメータに指定する文字位置・文字数はいずれもバイト単位であり、利用者に入力してもらったテキスト、
またはファイルから読み込んだテキストの一部を操作する時は、判別する必要があります。
文字コードには法則があり、コード値が129〜159ビットまたは224〜255ビットになる場合、
そのコードを含む文字は必ず全角(2バイト)文字になります。(但し、日本語Windowsの場合)
この法則を利用すれば、いずれかを判定することが出来るようになりますが、
全角文字の2バイト目は0〜255ビットのいずれも来る可能性があり、コレだけでは不完全です。
対象コードが1バイト文字領域だった場合、1バイト前も1バイト文字領域ならば、
対象文字コードは「半角文字」であることが分かりますが、1バイト前が2バイト文字領域なら、
対象コードは「半角文字」「全角文字の2バイト目」のいずれかであるため、
さらにもう1バイト前を見る必要があります。
もし、さらにもう1バイト前が1バイト文字領域なら、対象コードは「全角文字の2バイト目」ですが、
逆に1バイト前が2バイト文字領域なら、さらに前を確認しなければ対象コードを特定することは出来ません。
一方、対象コードが2バイト領域だった場合に、1バイト前が1バイト文字領域なら、
対象の2バイト文字領域コードは「全角文字の1バイト目」になります。
1バイト前も2バイト文字領域なら、さらにもう1バイト前を確認する必要があります。
もし、さらにもう1バイト前が1バイト文字領域なら、対象コードは「全角文字の2バイト目」ですが、
逆に1バイト前が2バイト文字領域なら、さらに前を確認しなければ対象コードを特定することは出来ません。
整理すると次の様な法則が成り立ちます。

2バイト前1バイト前対象位置結果
確認不要1バイト文字1バイト文字対象コード=半角文字
1バイト文字2バイト文字1バイト文字対象コード=全角文字の2バイト目
2バイト文字2バイト文字1バイト文字ここからは判断できない
確認不要1バイト文字2バイト文字対象コード=全角文字の1バイト目
1バイト文字2バイト文字2バイト文字対象コード=全角文字の2バイト目
2バイト文字2バイト文字2バイト文字ここからは判断できない

つまり、対象位置より前の1バイト文字領域コードが出てくるまで確認することでOKなわけです。

wordchk 対象変数, 位置
対象変数判別したい文字列の入った変数を指定する。
statに-1(範囲外)、0(半角)、1(全角)のいずれかがセットされる。
位置指定変数の位置をバイト単位で指定する。

bytechk 対象変数, 位置
対象変数判別したい文字列の入った変数を指定する。
statに-1(範囲外)、0(半角)、1(全角1バイト目)、2(全角2バイト目)のいずれかがセットされる。
内部でwordchk命令を使用しているため、bytechk命令の前にwordchk命令を定義すること!
位置指定変数の位置をバイト単位で指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#module
#deffunc wordchk val, int
	mref txt, 24 : mref ichi, 1
	mref stt, 64
	peek chk, txt, ichi
	if chk = 0 : stt = -1 : return // 範囲外
	if (chk > 128 & (chk < 160)) | (chk > 223) : stt = 1 : else : stt = 0 // 1byte=0 2byte=1
	return

#deffunc bytechk val, int
	mref s, 24 : mref p, 1
	mref stt, 64
	// 対象コードをチェックする
	wordchk s, p
	code = stat
	if code = -1 : return // 範囲外
	// 対象コードより前を確認
	repeat , 1
		wordchk s, p - cnt
		// 全てをチェックし終わったか、1バイト文字が来た
		if (stat = -1) || (stat = 0) {
			if code = 0 {
			  // 1バイト領域になったのが奇数回なら半角、偶数回なら全角2バイト目
			  if cnt \ 2 = 1 : stt = 0 : else : stt = 2
			} else {
			  // 1バイト領域になったのが奇数回なら全角1バイト目、偶数回なら全角2バイト目
			  if cnt \ 2 = 1 : stt = 1 : else : stt = 2
			}
			break
		}
	loop
	return
#global

	sdim type, 24, 3
	string = "abあcdeいfうghえijおklmかnopきqくrsけtuvこwxyz"
	type = "1バイト文字","2バイト文字1バイト目","2バイト文字2バイト目"
	strlen len, string
	randomize
	font "MS 明朝", 12
	color 255
	pos 30, 20 : mes string
	color , , 255
	pos  30,  5 : mes "01234567890123456789012345678901234567890123456789"
	pos  30, 50 : mes "位置"
	pos  80, 50 : mes "文字"
	pos 150, 50 : mes "タイプ"
	color
	repeat 25
		rnd r, len
		bytechk string, r // 適当な位置のコードをチェックする
		switch stat
			case 0: strmid get, string, r, 1 : swbreak
			case 1: strmid get, string, r, 2 : swbreak
			case 2: strmid get, string, r - 1, 2
		swend
		pos  30, cnt * 15 + 65 : mes r
		pos  80, cnt * 15 + 65 : mes get
		pos 150, cnt * 15 + 65 : mes type.stat
	loop
	stop

結果 = wordchk(対象変数, 位置)
結果-1(範囲外)、0(半角)、1(全角)のいずれかがセットされる。
対象変数判別したい文字列の入った変数を指定する。
位置指定変数の位置をバイト単位で指定する。

結果 = bytechk(対象変数, 位置)
結果-1(範囲外)、0(半角)、1(全角1バイト目)、2(全角2バイト目)のいずれかがセットされる。
内部でwordchk命令を使用しているため、bytechk命令の前にwordchk命令を定義すること!
対象変数判別したい文字列の入った変数を指定する。
位置指定変数の位置をバイト単位で指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#module
#defcfunc wordchk var s, int ichi
	if ichi < 0 : return -1 // 範囲外
	chk = peek(s, ichi)
	if (chk > 128 & chk < 160) | chk > 223 : return 1 // 2byte=1
	if chk = 0 : return -1 : else : return 0          // 1byte=0 範囲外=-1

#defcfunc bytechk var txt, int p, local code, local stt
	// 対象コードをチェックする
	code = wordchk(txt, p)
	if code = -1 : return // 範囲外
	// 対象コードより前を確認
	repeat , 1
		stt = wordchk(txt, p - cnt)
		// 全てをチェックし終わったか、1バイト文字が来た
		if (stt = -1) | (stt = 0) {
			if code = 0 {
			  // 1バイト領域になったのが奇数回なら半角、偶数回なら全角2バイト目
			  if cnt \ 2 = 1 : stt = 0 : else : stt = 2
			} else {
			  // 1バイト領域になったのが奇数回なら全角1バイト目、偶数回なら全角2バイト目
			  if cnt \ 2 = 1 : stt = 1 : else : stt = 2
			}
			break
		}
	loop
	return stt
#global

	sdim type, 24, 3
	string = "abあcdeいうfghえijおklmかnopきqくrsけtuvこwxyz"
	type = "1バイト文字","2バイト文字1バイト目","2バイト文字2バイト目"
	len = strlen(string)
	randomize
	font "MS 明朝", 12
	color 255
	pos 30, 20 : mes string
	color , , 255
	pos  30,  5 : mes "01234567890123456789012345678901234567890123456789"
	pos  30, 50 : mes "位置"
	pos  80, 50 : mes "文字"
	pos 150, 50 : mes "タイプ"
	color
	repeat 25, 3
		r = rnd(len)
		// 適当な位置のコードをチェックする
		switch bytechk(string, r)
			case 0: get = strmid(string, r, 1) : swbreak
			case 1: get = strmid(string, r, 2) : swbreak
			case 2: get = strmid(string, r - 1, 2)
		swend
		pos  30, cnt * 15 + 20 : mes r
		pos  80, cnt * 15 + 20 : mes get
		pos 150, cnt * 15 + 20 : mes type.stat
	loop