ascii( ) 関数についてNo.02670
杉浦 まさき さん 01/11/24 04:05
 
皆さんこんばんは。
杉浦 まさき です。
先日秀丸会議室でマクロの文字列系関数の2バイト文字絡みの
話題が出ていたのでもしかしたら既出かもしれませんが、
個人的には結構ショッキングな(笑)発見だったので
その勢いで書いてしまいます(^^;。

ascii() 関数を2バイト文字に対して適用した場合
2バイト分をまとめて 16bit 整数として返す、
という仕様ですが、以下のようにわざと2バイト文字の
1バイト目(コード=0x??)を切り出した
(1文字からなる)文字列に適用すると、
0x??00 という値が返ってくるんですねぇ…今まで気づかなかった(笑)。

 $a = midstr("あ", 0, 1); // 2バイト文字の1バイト目を切り出す message str
(ascii($a)); // == 33280 == 0x8200 が返る
というわけで、

 if (ascii(midstr($s, #i, 1)) & 0x80) {
   // 2バイト文字の1バイト目だった
 }

というかっこいい(笑)コードはNGで、

 if (ascii(midstr($s, #i, 1)) > 0x7F) {
   // ..
 }

というコードは(Win32 環境では)正常に動作する、と。いや〜、デバッグしててずい
ぶん悩みました(苦笑)。

[ ]
RE:02670 ascii( )関数についてNo.02675
TAKA さん 01/11/24 11:59
 
TAKA です。

>ascii() 関数を2バイト文字に対して適用した場合
>2バイト分をまとめて 16bit 整数として返す、
>という仕様ですが、以下のようにわざと2バイト文字の
>1バイト目(コード=0x??)を切り出した
>(1文字からなる)文字列に適用すると、
>0x??00 という値が返ってくるんですねぇ…今まで気づかなかった(笑)。

どのような仕様が正解とは言えませんが、現状(0x8200)でも、0x82、
0xA0、でも良いと思います。
2バイトも文字を途中で切って取り出すこと自体がやってはいけな
いことだと思いますので。

[ ]
RE:02675 ascii( )関数についてNo.02676
杉浦 まさき さん 01/11/24 20:56
 
TAKA さん、こんばんは。
杉浦 まさき です。

>どのような仕様が正解とは言えませんが、現状(0x8200)でも、0x82、
>0xA0、でも良いと思います。

0x82 が1バイト文字としては不正な値なので、
その場合に ascii( ) 関数がどういう動作をしても
文句をいう筋合いはないのは確かです。
#でも ascii(midstr("あ", 0, 1)) で 0xA0 を返すのは
 さすがに止めてほしいですが(^^;。

>2バイトも文字を途中で切って取り出すこと自体がやってはいけな
>いことだと思いますので。

やっていいか悪いかは何ともいえませんが、
ただ、文字列を1バイトずつなめていって…という処理を書くときに、
直感的に

 #len = strlen($s);
 #a = 0;
 while (#a < #len) {
   #c = ascii(midstr($s, #a, 1));
   if (#c & 0x80) {
     // 2バイト文字だった場合
     ...
     #a = #a + 1;
   }
   #a = #a + 1;
 }
と書くと駄目というのに単純に「びっくりした」だけです(^^;。

何か意図が見えにくい発言だったなぁと反省してますが、
バグ報告でも仕様変更の要求でもなく、
単なる「感想」として捉えて頂ければ幸いです。


[ ]
RE:02676 ascii()関数についてNo.02679
TAKA さん 01/11/25 03:54
 
TAKA です。

>バグ報告でも仕様変更の要求でもなく、
>単なる「感想」として捉えて頂ければ幸いです。

そうでしたか。失礼しました。
次のQ&Aには、
ascii(midstr($s, #a, 2));
にする必要がある(安全のためにも)というのも追加しておいた方
がよさそうですね。

[ ]
RE:02679 ascii()関数についてNo.02680
杉浦 まさき さん 01/11/26 00:50
 
TAKA さん、こんばんは。
杉浦 まさき です。

>>バグ報告でも仕様変更の要求でもなく、
>>単なる「感想」として捉えて頂ければ幸いです。
>そうでしたか。失礼しました。

いえいえ、こちらこそ。
あんまり驚いたのでつい勢いで書いてしまったものでして…(^^;。

>次のQ&Aには、
>ascii(midstr($s, #a, 2));
>にする必要がある(安全のためにも)というのも追加しておいた方
>がよさそうですね。

もう少し具体的に、2バイト文字かどうかの判定は
以下のように書きましょう、てな感じですかねぇ。
#ascii(..) > 0x7F でも(16bit 版でなければ(^^;)OKですけど。

 if (ascii(midstr($s, #a, 2)) & 0xFF00) {
   // 2バイト文字だった場合
 }

前回書いたようなCライクな書き方だと駄目だというのが肝ですが、
想定されるQ&A集の読者層を考えるとそこまで言及するのは
やりすぎかもしれませんね…。

#前回報告した仕様を考えると、
 midstr() の第3引数の文字数は >= 1 であればいいですね。
 でも 1 にすると何をやりたいのかわかりにくくなるんで、
 2 (以上)を指定するやり方が一番自然だと思います。


[ ]
RE:02680 ascii()関数についてNo.02685
TAKA さん 01/11/26 12:55
 
まいどっ、TAKA です。
杉浦さんも、凄い時間まで起きてますね。
#人のことは言えませんが。

>もう少し具体的に、2バイト文字かどうかの判定は
>以下のように書きましょう、てな感じですかねぇ。
>#ascii(..) > 0x7F でも(16bit 版でなければ(^^;)OKですけど。
>
> if (ascii(midstr($s, #a, 2)) & 0xFF00) {
>   // 2バイト文字だった場合
> }

可能であれば、「#01879 2001/03/22」で書いたビット演算と
「#01884 2001/03/22」で書いた負の表現(1の補数表現と2の補
数表現)方法について、整理して書ければいいなーと思っています。


>前回書いたようなCライクな書き方だと駄目だというのが肝ですが、
>想定されるQ&A集の読者層を考えるとそこまで言及するのは
>やりすぎかもしれませんね…。

通常のQ&Aには、
if (ascii(midstr($s, #a, 2)) & 0xFF00)
のようなソースコードだけを書いて(既にある)、より詳しく知り
たい人のために上記の解説を別ページに設けたらと良いと考えてい
ます。

[HMM0073A]
「●文字列をバイト単位ではなく文字単位で扱う」に、
ビット演算の詳細は、「●ビット演算」を参照して下さい。という
のを追加するような形。


余談ですが、真と偽についても、同様に専用ページを設けたいです。
普通のQ&Aには、以下のような記述で。

Q.真とか偽というのは何のことでしょうか?
A.条件式(if文など)を評価するには、真(0以外)か偽(0)で
判断します。
詳細は、「●真と偽について」を参照して下さい。

Q.while( 1 )は何をするものでしょうか?
A.これは条件式の判断が真(0以外)か偽(0)で処理されること
を利用して、無限ループを作っています。
詳細は、「●真と偽について」を参照して下さい。


正月にでも時間が取れればいいのですが・・・・
#今度も、ひろさんから誰かにお願いする可能性が、無きにしも非
 ず。


P.S.
Q&A集の会議室の期間延期を依頼していますか? > 作成メンバー
#もう、依頼済みだったかな?
まあ、黙認はして頂いていると思いますが。

[ ]