〜 文字列編 〜

01閏年かどうか調べる

02.変数内の数値・文字列を別の変数の内容と交換する

03.文字列を暗号化する

04.DLLを使わずにソート(並べ替え)をする

05.数値の桁そろえをする

06.rndで重複しない数値を取り出す

07.英小文字・大文字変換

08.1バイト2バイト文字の判別

09.時間挿入

10.時間取得モジュール

11.余分文字を取り除くモジュール

12.DLLを使わずにCSVをメモリノートに変換するモジュール

13.DLLを使わずにCSVを配列に変換するモジュール

14.メモリノート形式をCSVに変換するモジュール

15.16進数→10進数変換

16.基数変換

17.英字小文字化・大文字化・大小反転モジュール

18.32768以上にも対応した乱数発生モジュール

19.文字列の中央寄せモジュール

20.文字列の右寄せモジュール

21.3桁区切りのコンマを入れてみる

22.ウィンドウの端まで来たら自動で折り返す文字列表示モジュール

23.タブ「\t」をHSPでも使ってみるモジュール

24.半角の数値を全角に変換するモジュール

25.ポインタの変化でデータ高速並び替え

26.32bit値以上の加減算をするモジュール

27.後入れ先出し(LIFO)モジュール

28.先入れ先出し(FIFO)モジュール

29.標準命令だけでllmod.asのcharlower,charupperと同じことをする

30.S-JISからEUCに変換するモジュール

31.EUCからS-JISに変換するモジュール

32.小数点以下があっても加算できるモジュール

33.小数点以下があっても減算できるモジュール

34.小数点以下があっても乗算できるモジュール

35.小数点以下があっても除算できるモジュール

36.文章をゆっくり端から表示するモジュール

37.グラデーション文字2(モジュール版)

 


01.閏年かどうか調べる

  知らない方はいないでしょうが一応説明。閏年とは4年に1度ズレを修正するために2月に1日プラスされる年です。
  カレンダー関係のプログラムを組む方はコレに気を付けないと「2月29日問題」が生じてしまいます。
  4年に1度2月29日があるわけですが、実は例外があります。
  100で割り切れる年(1900年,2100年など)は閏年にはならないのです。
  さらに例外があり100で割り切れて400でも割り切れる年(1600年,2000年)は閏年になるのです。
  少々面倒くさいですが取り入れましょう。「2100/02/29」とならないように。。。

  (例)年を入力し閏年かをチェックする

 screen 0,200,50
 pos 5,10 : input year,60,30,4 ; 年を入力するボックス
 objsize 100,30
 pos 80,10 : button"チェック",*seach
 stop

*seach
 flg=0 ; フラグを初期化する
 if year\4=0{ ; 4で割り切れるかチェック
  flg=1 ; 4で割り切れたらとりあえず閏年の候補とする
  if year\100=0{ ; さらに100で割り切れるかチェック
   flg=0 ; 100で割り切れたら閏年候補を取り消す
   if year\400=0{ ; さらに400で割り切れるかチェック
    flg=1 ; 400で割り切れたらまた候補にする(必ず閏年ですが)
   }
  }
 }
 if flg=1{ ; 閏年の候補ならダイアログボックスを表示
  dialog ""+year+"年はうるう年です"
 }else{
  dialog ""+year+"年はうるう年ではないです"
 }
 stop

TOPへ戻る

02.変数内の数値・文字列を別の変数の内容と交換する

  変数Aの内容(例としてabcde)と変数B(xyz)をAにxyz、Bにabcdeと入れ替えるには、
  それぞれの交換する変数と一時変数の3つを使用します。
  このアルゴリズムは基本ですので知らない方は覚えておいて損はないです。

  (例)inputの内容を入れ替える

 a="文字列1"
 b="文字列2"
 input a,200,25,64
 input b,200,25,64
 button"change",chg
 stop

*chg
 tmp=a
 a=b
 b=tmp
 objprm 0,a
 objprm 1,b
 stop

  論理演算を行えば2つだけで行うことが出来ますが数値のみです。

 a=123 : b=987
 mes "変換前 a="+a+" b="+b
 a=a^b
 b=b^a
 a=a^b
 mes "変換後 a="+a+" b="+b
 stop

TOPへ戻る

03.文字列を暗号化する

  サウンドノベルのシナリオ等のデータがエディターで簡単に開けてしまうと
  先の展開が分かってしまって面白くなくなってしまいます。
  対策として、こういったテキストファイルは他人が見ても分からないように暗号化して、
  ソフト側からロードする際に復号化して利用することで回避できると思います。
  暗号化したモノをmesbox等に表示する場合、注意すべきポイントは、
  文字列内にNULL文字が存在するとNULL文字以降の内容は表示されないことです。
  NULL文字を検索し、NULL文字を別の文字に変更したものを別の変数に代入し表示しましょう。

  (例)ビット反転による暗号化

 sdim buf,64000,2 ;実際の文字列が入る変数とNULLを別の文字に変更したのが入る変数、二つ用意する
 sdim file,256
 key=100 ; 暗号鍵(0〜255の間の数値にしましょう)
 objsize 640,25
 button"暗号 / 復号",cipher
 mesbox buf.1,640,455 ;書き換え不可のテキストボックス
 dialog "txt",16
 if stat=0 : end
 bload refstr,buf
 file=refstr
 size=strsize
 if size>64000 : dialog"サイズが大きすぎます" : end ;サイズが約64KB以上なら終了する
 goto *disp

*cipher
 repeat size
  peek tmp,buf,cnt
  tmp=tmp^key ; ココがビット反転
  poke buf,cnt,tmp
 loop

*disp
 repeat size
  peek tmp,buf,cnt
  if tmp=0 : tmp=' ' ;取り出した文字がNULLなら半角スペースに置き換える
  poke buf.1,cnt,tmp ;NULLをスペースに置き換えながら一文字ずつ表示用変数に入れていく
 loop
 objprm 1,buf.1
 stop

TOPへ戻る

04.DLLを使わずにソート(並べ替え)をする

  文字列の並べ替えは少々面倒くさいですが、DLLなしで実現できます。

  (例)文字列の先頭文字を見比べて大小を決めソートする

 sdim m,64,2 ; 比較する文字列
 sdim moji,256 ; 比較される文字列
 moji="asd33z\nasd32499\nasd324あ\nasd3A\nasd33z\nasd3249989"
 mes ""+moji+"\n---------------------"
 notesel moji
 notemax kazu ; 最終行までソートを繰り返せるように行数を取得
 i=0 ; 比較する文字列の行数
 repeat kazu-1
  repeat kazu-1-i
   noteget m.0,i
   peek m1,m.0,ichi ; ichiは比較対照文字の位置(初めは0)
   noteget m.1,i+cnt+1
   peek m2,m.1,ichi
   if m1>m2{ ;  比較する側が大きければ入れ替える(m1<m2とすると降順でソート)
    notedel i
    noteadd m.1,i
    notedel i+cnt+1
    noteadd m.0,i+cnt+1
   }
   if m1=m2{ ; 比較対照文字が同じ文字だった場合の処理
    ichi++ ; 次の文字を比較対照に変更
    continue cnt ; 先ほどの繰り返しをやり直す
   }
   ichi=0 ; 比較対照文字を1文字目に戻しておく
  loop
  i++
 loop
 mes moji
 stop

TOPへ戻る

05.数値の桁そろえをする

  数値を画面上に表示すると文字列と同じように左詰で表示されてしまいます。
  strを使えば「00250」のようにゼロを入れて桁をそろえることが出来ます。
  ゼロが入るのが嫌と言う方は下のサンプルをお試しください。

  (例)桁そろえをする

 dim ten,3
 ten=250,10,1024 ; 「ten.0=250:ten.1=10:ten.2=1024」と書いたのと同じ意味
 repeat 3
 tmp="   "+ten.cnt ; (そろえたい桁数-1)個スペースを用意
 strmid tmp,tmp,-1,4 ; 最後の「4」の所に揃えたい桁数を指定
 mes tmp
 loop
 stop

TOPへ戻る

06.rndで重複しない数値を取り出す

  変数や配列を100個用意し、それぞれに0〜99の数値を重複することなく入れていくには、
  1度使った値を記憶させて行けばよいわけです。
  同じ数値が以前に使われたかチェックし、使われていたらもう一度乱数を取り出す。
  コレを繰り返すことによりすべてに違った値を入れることが出来るのです。

  (例)重複しない乱数を作成する(0〜200の数値)

 dim buf,2,200 ; 200個入れる変数を二つ用意(0は乱数を入れる,1は重複のチェック用)
 randomize

*random
 repeat 200
  await 0 ; タスクを回す(数が多くなると終了するまで操作ができなくなる為)
  rnd rand,200 ; とりあえず乱数作成
  buf.0.cnt=rand ; 「buf.0.(0〜順に199まで)」に乱数を入れる
  if buf.1.rand=1 : continue cnt ; 「 buf.1.(乱数)」に1が入っているとやり直し
  buf.1.rand=1 ; 「buf.1(乱数)」に1を入れて同じ数値を使えないようにする
  prg=cnt/2 ; 必要なし(現在の進行状態を入れる変数です)
  title ""+prg+"%完了" ; 必要なし(タイトルバーに進行状態を表示する)
 loop

*print_num
 title "100%完了"
 dialog"ランダムな数値を表示させますか?",3,"完了"
 if stat=7 : end
 x=35:y=5
 font "MS ゴシック",12,0
 color 200,0,0 : pos 5,5:mes "番号"
 color 0,0,0 : pos 5,20:mes "乱数"
 repeat 200
  num=cnt ; 必要なし(番号表示)
  str num,3 ; 必要なし(番号を3けたに合わせる)
  color 200,0,0 : pos x,y : mes num
  color 0,0,0 : pos x,y+15 : mes buf.0.cnt
  x+=25
  if x>610 : x=35 : y+=45 ; 画面の右端に来た時に左端の一段下にカレントポジション移動
 loop
 stop

TOPへ戻る

07.英小文字・大文字変換

  アルファベットを小文字化or大文字化するにはアスキーコードと呼ばれる文字を数値で表したモノに一度変換します。
  HSP内部ではもともとこのアスキーコードで管理しているわけですが・・・。

コード表 0 1 2 3 4 5 6 7 8 9
30     空白 ! " # $ % & '
40 ( ) * + , - . / 0 1
50 2 3 4 5 6 7 8 9 : ;
60 < = > ? @ A B C D E
70 F G H I J K L M N O
80 P Q R S T U V W X Y
90 Z [ \ ] ^ _ ` a b c
100 d e f g h i j k l m
110 n o p q r s t u v w
120 x y z { | } ~      

  この表の見方は、1番左が10と100の位です。
  上が1の位で、例えば「/」は40と7の交差点と言うことでコードは47となります。
  で、本題なのですが、まず大文字の「A」を見てください。65です。小文字の「a」はというと97です。
  つまりAのコードに32足せばaになるわけです。Bも32足せばbになります。
  文字を数値に変換するにはpeek,数値を文字にするにはpoke命令を使用します。

  (例)小文字←変換→大文字

 buf="ABCdeFghIJklm"
 objsize 100,25
 input buf,300,25,30
 button "変換",*change
 stop

*change
 strlen len,buf
 repeat len
  peek moji,buf,cnt
  if (moji>=65)&(moji<=90) : moji+=32 : else : if (moji>=97)&(moji<=122) : moji-=32
  poke buf,cnt,moji
 loop
 color 255,255,255 : boxf
 color
 pos 10,100 : mes buf
 stop

TOPへ戻る

08.1バイト2バイト文字の判別

  文字には1バイト文字と2バイト文字が存在します。そう全角・半角文字と呼ばれる奴ですね。
  peek命令を使用すれば気づきますが、2バイト文字の1バイト目の値は必ず「129から159、または224以上」となります
  これを覚えておけば、例えば文字数を数えることなどが容易にできます。

  (例)文字を数える

 buf="1byte、2byte文字混合の文字数を調べる"
 mes buf
 repeat
  peek tmp,buf,ichi
  if tmp>128&(tmp<160)|(tmp>223) : ichi+=2 : else : ichi+
  if tmp==0 : break
  moji+
 loop
 mes "文字数は"+moji+"文字です"
 stop

TOPへ戻る

09.時間挿入

  メモ帳等の時間の挿入はどうするのでしょうか?
  gettime命令で時間を取得し、08の方法でクリップボードを操作して貼り付けてみましょう。

  (例)文字を数える

 sdim buf,16000
 buf=""
 mesbox buf,640,460,1
 objsize 640,20
 button "時間貼り付け",now
 pos 0,-20 : input clip,100,20
 stop

*now
 gettime time.0,4 ; 時間
 gettime time.1,5 ; 分
 gettime time.2,6 ; 秒
 clip=""+time+":"+time.1+"."+time.2
 strlen mojiend,clip
 objprm 2,clip
 a=0
 objsend 2,$b1,0,mojiend,1 ; 取得時間を選択
 objsend 2,$300,0,a,1 ; クリップボードに送る
 objsend 0,$302,0,a,1 ; キャレット位置にクリップボード内容貼り付け
 stop

TOPへ戻る

10.時間取得モジュール

  gettime命令で日付・時間を毎回取得するのは意外と面倒ですよね。
  こういう時は何度でも再利用できるようにモジュールにしてしまいましょう。
  時間まとめて取得する命令の書式は「now 取得したものを入れる変数,取得するもの」です。
  p2の取得するものは
  1で年
  2で月
  4で曜日
  8で日
  16で時
  32で分
  64で秒
  128でミリ秒を取得し、取得したい物が複数ある場合は取得したい物の値を足してください。

  (例)時間取得

;************ 概要説明 ************
;
; now p1,p2
;
; p1=変数 : 取得した日時を代入する変数
; p2=1〜 : 取得するもの
;
;**********************************
#module "time"
#deffunc now val,int
 mref time,24
 mref get,1
 sdim day,3,7
 day="日","月","火","水","木","金","土"
 time=""
 if get&1 : gettime tmp,0 : time+=""+tmp+"年"
 if get&2 : gettime tmp,1 : time+=""+tmp+"月"
 if get&8 : gettime tmp,3 : time+=""+tmp+"日"
 if get&4 : gettime tmp,2 : time+="("+day.tmp+")"
 if get&16 : gettime tmp,4 : time+=""+tmp+"時"
 if get&32 : gettime tmp,5 : time+=""+tmp+"分"
 if get&64 : gettime tmp,6 : if get&128 : tmp.1=tmp : else : time+=""+tmp+"秒"
 if get&128 : gettime tmp,7 : if get&64 : time+=""+tmp.1+"."+tmp+"秒" : else : time+="0."+tmp+"秒"
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 repeat
  redraw 0
  color 255,255,255 : boxf : color
  now nowtime,112 ; 新取得命令(時間・分・秒を取得する)
  pos 0,0 : mes nowtime
  redraw
  wait 100
 loop

TOPへ戻る

11.余分文字を取り除くモジュール

  変数の中に邪魔な文字が不特定の場所にあり、それらをすべて取り除きたい場合に利用しましょう。
  文字列ではなく文字のASCIIコードを指定してください。
  変数内の余計な文字を取り除いたものがシステム変数refstrに返ってきます。

  (例)ハイフン(-)を取り除く

;************ 概要説明 ************
;
; remove p1,p2
;
; p1=0〜255 : 余分文字のキャラクタのASCIIコード
; p2=変数  : 余分文字を抜きたい変数
;
;**********************************
#module "removes"
#deffunc remove int,val
 mref excess,0
 mref variable,25
 mref result,65
 strlen len,variable
 repeat len
  peek tmp,variable,cnt
  if evasion>0 : evasion--
  if tmp>128&(tmp<160)|(tmp>223) : evasion=2 ; 2バイト文字の場合下位バイトは除去を無視する
  if tmp==excess&(evasion==0) : continue
  poke result,num,tmp
  num+
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 buf="abc-def-ghij-klm-n-opq-rs-tu-vw-xyz" ; 元となる変数
 remove '-',buf ; ASCIIコードを指定するかシングルクォートで囲んだ文字を指定する
 mes refstr
 stop

TOPへ戻る

12.DLLを使わずにCSVをメモリノートに変換

  hspda.dllにCSV(,で区切られたデータ)をメモリノート(1行が1つのデータ)に変換する命令がありますが
  コレだけのためにDLLを使うのが嫌という方は下記のモジュールを使用してみてください。
  hspda.dllではp2に文字列か文字列変数のどちらでもいけましたが、
  この命令は文字列変数しかご利用いただけません。文字列だとエラーが出てしまいます。
  文字列で使用したいという方は、ご自分でサンプルを変更してください。

  (例)CSVをメモリノートに変換

;************ 概要説明 ************
;
; csvtonote p1,p2
;
; p1=結果が代入される文字列型の変数名
; p2=CSV形式の文字列変数名
;
;**********************************
#module "csv"
#deffunc csvtonote val,val
 mref result,24
 mref origin,25
 repeat
  getstr tmp,origin,ichi,','
  if cnt>0 : result+="\n"
  result+=tmp
  instr chk,origin,",",ichi
  if chk==-1 : break
  strlen len,tmp
  ichi+=len+1
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 buf=",a,b,c,d,,e"
 csvtonote buf2,buf
 mes buf2
 stop

TOPへ戻る

13.DLLを使わずにCSVを配列に変換

  12をやったついでにhspda.dllの他のものもやってしまおうということでやってみました。
  hspda.dllにCSVを配列変数に入れる命令が存在しますがDLLを使うのが嫌という方のために。
  DLLは、オーバーフロー(配列の限界を越えた)したとき越えた部分は無視されますが、
  下記のモジュールはエラーになってプログラムを中断してしまいます。
  あらかじめオーバーフローしないように大きめに確保しておいてください。

  (例)CSVを配列に代入

;************ 概要説明 ************
;
; csvtostr p1,p2
;
; p1=結果が代入される文字列型の配列変数名
; p2=CSV形式の文字列変数名
;
;**********************************
#module "csv"
#deffunc csvtostr val,val
 mref result,56
 mref origin,25
 repeat
  getstr tmp,origin,ichi,','
  result.cnt=tmp
  instr chk,origin,",",ichi
  if chk==-1 : break
  strlen len,tmp
  ichi+=len+1
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 count=10 ; 配列変数の要素最大数
 sdim buf2,2,count
 buf=",a,b,c,d,,e,f,g"
 csvtostr buf2,buf
 repeat count
  mes buf2.cnt
 loop
 stop

TOPへ戻る

14.メモリノートをCSVに変換

  12の逆バージョンもついでにやってしまおうというものです。
  なぜかDLLにはこの命令が存在しませんでした。必要のない命令なのかもしれませんね…。

  (例)メモリノートからCSV形式

;************ 概要説明 ************
;
; notetocsv p1,p2
;
; p1=結果が代入される文字列型の配列変数名
; p2=メモリノートの文字列変数名
;
;**********************************
#module "csv"
#deffunc notetocsv val,val
 mref result,24
 mref origin,25
 notesel origin
 notemax max
 repeat max
  noteget tmp,cnt
  if cnt!=0 : result+=","
  result+=tmp
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 buf="a\nb\nc\n\nd\ne\nf"
 notetocsv buf2,buf
 mes buf2
 stop

TOPへ戻る

15.16進数→10進数変換

  HSPには10進数から16進数には簡単に変換できますが、逆は載ってませんので自前で作成しました。

  (例)16→10

;************ 概要説明 ************
;
; hexchg p1
;
; p1="strings" : 16進数
;
;**********************************
#module "CardinalNumberChange"
#deffunc hexchg val
 mref chgval,24
 mref stt,64
 strlen keta,chgval
 num=chgval
 chgval=0
 repeat keta,1
  peek tmp,num,keta-cnt
  if tmp<'0'|(tmp>'f') : break ; 変換元変数が正式な10進数以外のものが入っている場合終了
  if tmp>='a' : tmp-=87 : else : tmp-=48
  dignity=1
  repeat cnt-1
   dignity=dignity*16
  loop
  chgval+=dignity*tmp
 loop
 str chgval
 stt=chgval
 int stt
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 buf=98765
 mes "10進数 "+buf+"\n\n ↓\n"
 str buf,16
 mes "16進数 "+buf+"\n\n ↓\n"
 hexchg buf
 mes "10進数 "+buf
 stop

TOPへ戻る

16.基数変換

  15で16→10進数変換をしました。基数変換で使用するのは大体16,10,2進数のいずれかでしょう。
  ここでは2進数に変換したいと思います。(他のものへ変えたい場合は2〜32進数に対応したモジュールをご利用ください)

  (例)10→2

 buf=123 ; 変換元数値
 two=""
 repeat
  tmp=buf\2
  two=""+tmp+""+two
  buf=buf/2
  if buf=0 : break
 loop
 mes two
 stop

TOPへ戻る

17.英字小文字化・大文字化・大小反転モジュール

  07で英字を大小文字に変換するためにはpeek命令で取り出した値に+-32すれば変換できると説明しました。
  何回も変換しなければならないようなことがある場合、非常に面倒です。
  一つの命令だけでできるようにモジュール化してしまいましょう。

  (例)英字小文字化・大文字化・大小反転

;************************* 命令説明 *********************
;
; tagchg p1,p2
;
; p1=変数  : 変換する文字列型変数
; p2=0〜(0) : 0は大文字化,1は小文字化,それ以外は大小反転
;
;********************************************************
#module "alphabet"
#deffunc tagchg val,int
 mref tag,24
 mref size,1
 strlen len,tag
 repeat len
  peek tmp,tag,cnt
  if size=0 : if tmp>96&(tmp<123) : tmp-=32
  if size=1 : if tmp>64&(tmp<91) : tmp+=32
  if size>1 : if tmp>96&(tmp<123) : tmp-=32 : else : if tmp>64&(tmp<91) : tmp+=32
  poke tag,cnt,tmp
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 sdim msg,9,3
 msg="大文字化","小文字化","大小反転"
 buf="aBcdeFGHijKlmnOpQRstuvwxYZ"
 mes ""+buf+"\n---------------------------"
 repeat 3
  tmp=buf
  tagchg tmp,cnt ; 変数内の英字を0で大文字化,1で小文字化,その他で反転
  mes ""+msg.cnt+" "+tmp
 loop
 stop

TOPへ戻る

18.32768以上にも対応した乱数発生モジュール

  32768以上の乱数がほしくなった場合はどうしますか?乱数を二つ以上組み合わせればできないことはありませんね。
  しかし乱数の上限を不定にしたいとなった時どうしますか?
  そういったときに登場するのがモジュールでしょう。
  このrand命令と通常のrndの違う点が少しあります。

  ・乱数の上限が2147483647(HSPの標準で扱える最高値)
  ・randomizeで初期化しなくとも使える(逆に言うと毎回同じ擬似乱数の発生ができない)
  ・p2で指定する値が上限であるが0〜p2の値までがランダムに発生(「rand param,1」とすると0か1が発生)

  rnd同様0は入れないでください。エラーチェックしていませんので落ちてしまいます。

  (例)文字を数える

;****************** 命令説明 *****************
;
; rand p1,p2
;
; p1=数値型変数   : 読み込むための変数
; p2=1〜2147483647 : 乱数の最大値を指定する
;
;*********************************************
#module "random"
#deffunc rand val,int
 mref variable,16
 mref max,1
 dim r,10
 dim tmp,10
 dim num,4
 randomize
 r.0=max/1000000000
 r.1=max/100000000\10
 r.2=max/10000000\10
 r.3=max/1000000\10
 r.4=max/100000\10
 r.5=max/10000\10
 r.6=max/1000\10
 r.7=max/100\10
 r.8=max/10\10
 r.9=max\10
 repeat 10
  if r.cnt!=0 : num.1=cnt : break ; 最大桁位置取得
 loop
 num.2=0 ; 最大桁用オーバーフロー防止フラグ
 repeat 10
  num=9-cnt
  if num<num.1 : break ; 最大桁を超えたら終了
  num.3=num+1
  if num=num.1 {
   if num.2=0 : r.num+
   rnd tmp.cnt,r.num
   continue
  }
  rnd tmp.cnt,10
  if tmp.cnt>r.num : num.2=1
 loop
 variable=tmp.9*1000000000+(tmp.8*100000000)+(tmp.7*10000000)+(tmp.6*1000000)
 variable+=(tmp.5*100000)+(tmp.4*10000)+(tmp.3*1000)+(tmp.2*100)+(tmp.1*10)+tmp
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 repeat 10,1
  tmp=cnt
  repeat 25
   rand buf,54321
   mes buf
   wait 1
  loop
  pos tmp*65,0
 loop
 stop

TOPへ戻る

19.文字列の中央寄せ

  ここではありませんが本家掲示板にて質問があったものです。
  文字列を中央に表示するにはどうしたらよいかというものです。
  bmscr構造体を参照することで現在のフォントYサイズを取得できますので、
  コレを利用してXサイズを割り出し中央に寄せてみようというものです。
  この命令使用後のカレントポジションは中央よりのままですが、モジュール集のものはきちんと戻していますので…。

  (例)中央寄せ

;************ 概要説明 *************
;
; center p1
;
; p1 = "strings"
;
;**********************************
#module center
#deffunc center str
 mref string,32
 mref bmscr,67
 size=bmscr.32/2 ; フォントYサイズの2分の1がXサイズ?
 strlen len,string
 ichi=winx-(size*len)/2
 pos ichi,csry : mes string
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 font "MS ゴシック",80,1
 center "12345"
 color 255
 center "あいうえお"
 stop

TOPへ戻る

20.文字列の右寄せ

  19と同じような方法で文字列を右寄せにするにはどうしたらよいでしょうか。
  ほとんど同じやり方でできますね…。中央寄せと同じ所に書いてもよかったのですが…。
  19で書き忘れていたのですが注意する点は「等幅フォントを使用しなければ指定位置に来ない」と言う点です。

  (例)中央寄せ

;************ 概要説明 *************
;
; right p1
;
; p1 = "strings"
;
;**********************************
#module "right"
#deffunc right str
 mref string,32
 mref bmscr,67
 size=bmscr.32/2 ; フォントYサイズの2分の1がXサイズ?
 strlen len,string
 ichi=winx-(size*len)
 pos ichi,csry : mes string
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 font "MS ゴシック",90,1
 right "ABCDEFG"
 color 255
 font "MS 明朝",30
 right "9876543210"
 stop

TOPへ戻る

21.3桁区切りのコンマを入れてみる

  何かの値段を表示する時「\10,000」のように3桁区切りでコンマを表示する時がありますね。
  HSPで使われる数値もこの3桁区切りのコンマを入れたものに変えてみましょう。

  (例)10→2

 buf=1234567890
 str buf
 repeat
  strlen len,buf
  if len<3 : extraction=len : else : extraction=3
  strmid tmp,buf,-1,extraction
  if cnt : beam=""+tmp+","+beam : else : beam=tmp
  if extraction!=3 : break
  strmid buf,buf,0,len-3
 loop
 mes beam
 stop

  桁区切り(コンマ)を入れると数値型を文字列型に変換するため他の数値との計算ができなくなってしまいます。
  取り除くだけですから、別に11のコンマだけを取り除く方法でも構いませんが・・・
  簡単ですけどコンマを抜き数値にするやり方も書いておきます。

 beam="123,456,789"
 repeat
  strlen len,beam
  if len<3 : a=len : else : a=3
  strmid tmp,beam,-1,a
  if cnt : evaluation=""+tmp+""+evaluation : else : evaluation=tmp
  if a!=3 : int evaluation : break
  strmid beam,beam,0,len-4
 loop
 mes evaluation
 stop

TOPへ戻る

22.ウィンドウの端まで来たら自動で折り返す文字列表示モジュール

  ココであった質問ではないですけど他所であった質問の答えとして作成しました。
  mes命令ではウィンドウの右端まで来ても改行コードが来るまでそのまま続いて表示されてしまいます。
  常に監視し、はみ出しそうになったら自動で左端まで来るようにしています。
  この命令には「改行コード」を入れないでください。文字化けしてしまいます。

  (例)文字列自動折り返し命令

;************ 概要説明 *************
;
; retmes "strings"
;
; "strings" : 表示する255文字までの文字列
;
;**********************************
#module "retmes"
#deffunc retmes str
 mref string,32
 mref bmscr,67
 fsize=bmscr.32/2 ; 大体のXサイズ取得
 strlen len,string
 if len*fsize+csrx<winx : mes string : return
 mx=csrx
 my=csry
 repeat len
  peek tmp,string,cnt
  if tmp>128&(tmp<160)|(tmp>223) : tmp=2 : fsize=fsize*2 : else : tmp=1
  if mx+fsize>winx : mx=0 : my+=bmscr.32
  strmid msg,string,cnt,tmp
  pos mx,my : mes msg
  mx+=fsize
  if tmp=2 : fsize=fsize/2 : tmp=cnt+2 : continue tmp
 loop
 return
#global

 pos 150,20
 retmes "あabcいうxyzえお1234567890かきくけこabcdefghijklmnopqrstuvwxyzABC"
 stop

TOPへ戻る

23.タブ「\t」をHSPでも使ってみるモジュール

  本家掲示板の過去ログを漁っていたらloadlib.dllを使ってタブを入れるものを発見しました。
  私は22のTIPSを利用しててDLLを使わずにできないものかと思案し、実験してみました。
  多分コレでいけてるかと思いますけど何かおかしいところがあればおっしゃってください。
  一応タブのスペースは半角8文字分です。それと注意を1点。等幅フォントを使用するようにしてください。
  22は書き換えてません(書き換え予定なし)がコチラは「\t」が使えると言うことで「\n」も使える様にしています。
  またモジュール集に入れているretmesも改行OKとなっています。TIPSは重大なバグ以外書き換えませんので(^^;

  (例)文字列自動折り返し命令

;************ 概要説明 *************
;
; tab "strings"
;
; "strings" : 表示する255文字までの文字列
;
;**********************************
#module "tab"
#deffunc tab str
 mref string,32
 mref bmscr,67
 size=bmscr.32/2
 size.1=size
 strlen len,string
 mx=csrx : mx.1=csrx
 my=csry
 temp+=""
 repeat len
  peek tmp,string,cnt
  if tmp>128&(tmp<160)|(tmp>223) : tmp.1=2 : size=size*2 : else : tmp.1=1
  if mx+size>winx : mx=0 : my+=bmscr.32
  if tmp=9 : tmp.2=7-(tmp.3\8) : mx+=tmp.2*size : tmp.3+=tmp.2 : strmid msg,temp,0,tmp.2
  if tmp=13 : tmp.1=2 : tmp.3=0 : size=size*2 : msg="\n"
  if tmp!=9&(tmp!=13) : strmid msg,string,cnt,tmp.1
  pos mx,my : mes msg
  if tmp=13 : mx=mx.1 : my+=bmscr.32 : else : mx+=size
  if tmp.1=2 :size=size.1 : tmp=cnt+2 : continue tmp
  tmp.3+ ; 現在左から何文字目かを表わす
 loop
 return
#global

 sdim buf,256
 font "MS ゴシック",14
 buf ="12345678123456781234567812345678\n--------------------------------\n"
 buf+="abcde\tfg\nhij\tklmn\nopqrstu\tvwxyz\nAB\tCDEFG\nHIJKLMNOP\tQRSTU\tVWXYZ"
 pos 150,200
 tab buf
 stop

TOPへ戻る

24.半角の数値を全角にするモジュール

  英語の小文字大文字化と大して変わらないのですが質問があったものですので載せておきます。
  変換前は1バイトなのでpeekですが、変換後は2バイト文字ですのでwpokeを使います。
  peekで取り出すと0は48,1は49,2は50…となっています。変換後は何に変えればよいのでしょう?
  試しにwpeekで取り出してみると0は20354,1は20610,2は20866…と20354から256飛びに並んでいます。
  ですので変換は「48-変換前*256+20354」としてやれば思い通りのものになるはずですよね。
  コレを使えば英字の2バイト化等もできますね。

  (例)文字列自動折り返し命令

;************ 概要説明 *************
;
; halftofull p1,p2
;
; p1 : 変換後の数値(2バイト)を入れる変数
; p2 : 変換前の数値(1バイト)の入った変数
;
;**********************************
#module "halftofull"
#deffunc halftofull val,val
 mref p1,24
 mref p2,17
 tmp=p2
 str tmp
 strlen len,tmp
 p1=""
 repeat len
  peek half,tmp,cnt
  half=half-48*256+20354
  wpoke p1,cnt*2,half
 loop
 return
#global

 randomize
 rnd r,100000
 halftofull result,r
 mes ""+r+"\n\n ↓\n\n"+result
 stop

TOPへ戻る

25.ポインタの変化でデータ高速並び替え

  ある程度整列されているデータをある部分だけ別の部分のものと入れ替えるのはどのようにしますか?
  説明が不明ですね…例えば1,2,3,4,5,6,7,8,9,0というデータを1,2,3,8,9,0,4,5,6,7といった並び替えの場合です。
  こういった並び替えがよく使われるわけではありませんが、一応紹介しておこうと思います(^^;
  対象データをひとつずつずらしていくのはコレくらいの数ならまだしも1000くらいになると効率がよくありません。
  …ということでデータの位置をそのままで次に来るデータのポインタを変えてしまおうというものです。
  本来の使い方とは少し…いや結構違っていますが、ここでいうポインタとは指し示すもの「データのアドレス」です。
  まぁこの辺は元々のものと同じですけど…。
  別の同じ数だけの配列を用意しそれを次のデータのある位置を指し示すものとします。

  (例)50音順をあ→か→な→は→さ→た→ま→や→ら→わ行の順番に入れ替える

 arrangement=50 ; 必要な配列数
 sdim char,2,arrangement
 dim pointer,arrangement
 char.0 ="あ","い","う","え","お"
 char.5 ="か","き","く","け","こ"
 char.10="さ","し","す","せ","そ"
 char.15="た","ち","つ","て","と"
 char.20="な","に","ぬ","ね","の"
 char.25="は","ひ","ふ","へ","ほ"
 char.30="ま","み","む","め","も"
 char.35="や","","ゆ","","よ"
 char.40="ら","り","る","れ","ろ"
 char.45="わ","","を","","ん"
 repeat arrangement
  if cnt+1<arrangement:pointer.cnt=cnt+1:else:pointer.cnt=-1 ; 次のデータのあるアドレス(要素番号)を入れる
 loop
 pointer.9=20 ; 「こ」の次は「な」へ
 pointer.19=30 ; 「と」の次は「ま」へ
 pointer.29=10 ; 「ほ」の次は「さ」へ
 repeat
  pos cnt\5*40,cnt/5*20 : mes char.tmp ; 並び替えたデータ表示
  tmp=pointer.tmp
  if tmp=-1 : break
 loop
 stop

TOPへ戻る

26.32bit値以上の加減算モジュール

  HSPでは4バイト(32bit)整数しか扱えませんので、扱える範囲は-2147483648〜2147483647となります。
  ほとんどないでしょうけど2,147,483,647を超える数値の計算をするにはどうすればよいでしょう?
  私は文字列を使い演算しています。ココでは足し算と引き算を文字列のみ記載してあります。
  ただすべての加減算が出来るわけではなく正の整数の加減算のみとなっています。
  マイナス値の入った文字列型の数値は扱えません。ご自分で改良してみてください。

  (例)文字列自動折り返し命令

;************ 概要説明 *************
;
; add p1,p2    sub p1,p2
;
; p1 : 数値の入った文字列型変数1
; p2 : 数値の入った文字列型変数2
; refstr : 計算結果が返ります
;
;**********************************
#module "calc"
#deffunc add val,val
 mref val1,24
 mref val2,25
 mref result,65
 strlen len.1,val1
 strlen len.2,val2
 if len.1>len.2 : len=len.1 : else : len=len.2
 value=""
 repeat len,1
  strmid tmp1,val1,len.1-cnt,1
  strmid tmp2,val2,len.2-cnt,1
  int tmp1
  int tmp2
  tmp=tmp1+tmp2+tmp3
  str tmp,2
  strmid tmp3,tmp,0,1
  int tmp3
  strmid tmp,tmp,1,1
  value=tmp+""+value
 loop
 result=value
 return

#deffunc sub val,val
 mref val1,24
 mref val2,25
 mref result,65
 strlen len.1,val1
 strlen len.2,val2
 if len.1>len.2:len=len.1:reversal=0:else:len=len.2:reversal=1:tmp=len.1:len.1=len.2:len.2=tmp
 if reversal=1 : tmpstr1=val2 : tmpstr2=val1 : else : tmpstr1=val1 : tmpstr2=val2
 value=""
 repeat len,1
  if len.1-cnt>=0 : strmid tmp1,tmpstr1,len.1-cnt,1 : else : tmp1=0
  if len.2-cnt>=0 : strmid tmp2,tmpstr2,len.2-cnt,1 : else : tmp2=0
  int tmp1
  int tmp2
  if tmp1-tmp2>=0&(tmp3=1) : tmp1-
  if tmp1-tmp2<0 : tmp=10-tmp1-tmp2-tmp3 : tmp3=1 : else : tmp=tmp1-tmp2 : tmp3=0
  str tmp
  value=tmp+""+value
 loop
 if reversal=1 : value="-"+value
 result=value
 return
#global

 add1="9876543210"
 add2="12345678900"
 sub1="54321"
 sub2="12345678900"
 add add1,add2 ; 加算サンプル
 mes ""+add1+" + "+add2+" = "+refstr
 sub sub1,sub2 ; 減算サンプル
 mes ""+sub1+" - "+sub2+" = "+refstr
 stop

TOPへ戻る

27.後入れ先出し(LIFO)モジュール

  スタック(stack)やキュー(queue)といった言葉を聴いたことはないでしょうか?
  スタックとは下図のように後に入れたものを先に出す(先に入れたものを後に出す)データ構造の事を指します。
 
  今覚えさせていることをちょっと待って新しいものを先に先に使いたいといった場合に利用できるかと思います(^^;
  ちなみにLIFOはLastInFirstOutの略です。「先入れ後出し」よりFILOとも言うみたいですね。

  (例)LIFO機構

;************ 概要説明 *************
;
; spush p1,p2
;
; p1=数値型配列変数 : データを格納しておく配列変数
; p2=数値型変数   : 代入する数値データ
;
;
; pop p1,p2
;
; p1=数値型配列変数 : データが格納されている配列変数
; p2=数値型変数   : 取り出したデータを代入する数値型変数
;
;**********************************
#module "stack"
#deffunc spush val,val
 mref p1,48
 mref p2,17
 mref pval,1024
 repeat pval.2-1,1
  tmp1=pval.2-cnt-1
  tmp2=pval.2-cnt
  p1.tmp2=p1.tmp1
 loop
 p1.0=p2
 return

#deffunc pop val,val
 mref p1,48
 mref p2,17
 mref pval,1024
 p2=p1
 repeat pval.2
  tmp1=cnt+1
  if pval.2-1=cnt : p1.cnt=0 : else : p1.cnt=p1.tmp1
 loop
 return
#global

 dim variable,10 ; データを格納する変数
 tmp=50,100,150,200,250,300,400,500,1000,2000 ; 代入するデータ
 mes "入れていく"
 repeat 10
  spush variable,tmp.cnt
  mes tmp.cnt
 loop
 pos 200,0 : mes"取り出す"
 repeat 10
  pop variable,variable2
  mes variable2
 loop
 stop

TOPへ戻る

28.先入れ先出し(FIFO)モジュール

  27でスタックを解説しましたので先に入れたものを先に出すキューのデータ構造(FIFO)も書いておきます。
 
  詰め込むだけ詰め込めておいて、初めからデータを取り出していくことが必要な時にご利用ください。
  取り出す「pop」命令は27のものとまったく同じです。

  (例)FIFO

;************ 概要説明 *************
;
; qpush p1,p2
;
; p1=数値型配列変数 : データを格納しておく配列変数
; p2=数値型変数   : 代入する数値データ
;
;
; pop p1,p2
;
; p1=数値型配列変数 : データが格納されている配列変数
; p2=数値型変数   : 取り出したデータを代入する数値型変数
;
;**********************************
#module "stack"
#deffunc qpush val,val
 mref p1,48
 mref p2,17
 mref pval,1024
 repeat pval.2
  if p1.cnt!=0 : continue
  p1.cnt=p2
  break
 loop
 return

#deffunc pop val,val
 mref p1,48
 mref p2,17
 mref pval,1024
 p2=p1
 repeat pval.2
  tmp1=cnt+1
  if pval.2-1=cnt : p1.cnt=0 : else : p1.cnt=p1.tmp1
 loop
 return
#global

 dim variable,10 ; データを格納する変数
 tmp=50,100,150,200,250,300,400,500,1000,2000 ; 代入するデータ
 mes "入れていく"
 repeat 10
  qpush variable,tmp.cnt
  mes tmp.cnt
 loop
 pos 200,0 : mes"取り出す"
 repeat 10
  pop variable,variable2
  mes variable2
 loop
 stop

TOPへ戻る

29.標準命令だけでllmod.asのcharlower,charupperと同じことをする

  07でやった英大小文字化と08の1,2バイト判別の応用として、
  llmod.asにあった大小文字変換をするWinApiのCharLowerA,CharUpperAを標準命令でやってみました。
  当然全角の英文字が混じっていてもいけるようにはなっています。

  (例)WinAPIのCharLowerA(CharUpperA)を使わずに変数内の英字の大小文字を変換する

;************ 概要説明 *************
;
; lowerchar p1
;
; p1="strings" : 16進数
;
; upperchar p1
;
; p1="strings" : 16進数
;
;**********************************
#module "codechange"
#deffunc lowerchar val
 mref p1,24
 strlen len,p1
 ichi=0
 repeat len:wait 1
  peek tmp,p1,ichi
  if tmp>128&(tmp<160)|(tmp>223) {
   wpeek tmp,p1,ichi
   if tmp>=24706&(tmp<=31106) : tmp+=8448
   wpoke p1,ichi,tmp
   ichi+=2
   continue ichi
  }
  if tmp>=65&(tmp<=91) : tmp+=32
  poke p1,ichi,tmp
  ichi+
 loop
 return

#deffunc upperchar val
 mref p1,24
 strlen len,p1
 ichi=0
 repeat len:wait 1
  peek tmp,p1,ichi
  if tmp>128&(tmp<160)|(tmp>223) {
   wpeek tmp,p1,ichi
   if tmp>=33154&(tmp<=39554) : tmp-=8448
   wpoke p1,ichi,tmp
   ichi+=2
   continue ichi
  }
  if tmp>=97&(tmp<=122) : tmp-=32
  poke p1,ichi,tmp
  ichi+
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 buf="aBcdEfghijkLmnopqrstuVWxyz"
 upperchar buf
 mes buf
 buf="ABCDEFGhIJKLMnOpQrSTUVWxYz"
 lowerchar buf
 mes buf
 stop

TOPへ戻る

30.S-JISからEUCに変換するモジュール

  Unicodeの相互変換をloadlib.dllを使わずに標準だけでするモジュールを考えていたのですが、
  HSPver2.6がもうじき出て標準命令で使えてしまい(llmod.asは必要だが)意味がなくなるので中止しました(^^;
  とりあえずEUCの相互変換はできないようですのでコレを取り入れようかと…。
  知らない人用に説明するとEUCコードはUnixで標準使用されているコードで
  ネット上のデータを取り込んだら改行コードが「↑」こんなコードだったと言う経験があった人は少なくないはず…。
  これはWindowsの改行がCR+LF(キャリッジリターン+ラインフィード)であるのに対しUnixはLFだけで、
  WindowsではLFだけのコードでは「↑」このような文字が表示されるわけです。
  ですのでこんな文字の入ったデータはWindows用に直してやる必要があります。
  ソレをするのが…あ、コレはソレの逆のWindows→Unixですね。(^^;
  確認することのできるソフトをお持ちでない方は31で作成してください。
  使い方はllmod.asのto_uni(from_uni)と同じようにしています(やり方のパクリともいう)。
  第3パラメータに変換する文字列の長さを入れます。-1で全て変換、0で全変換に必要なバイト数がstatに返ります。
  気をつけることがありますが説明が長くなりすぎましたので31に書いています。

  (例)EUCに変換

;************ 概要説明 *************
;
; to_euc v1,v2,n3
;
; v1 : 変換したEUC文字列を入れる変数
; v2 : EUCに変換するS-JIS文字列が入った変数
; n3 : EUCに変換するS-JIS文字列の長さ
;
;**********************************
#module "codechange"
#deffunc to_euc val,val,int
 mref p1,24
 mref p2,25
 mref p3,2
 mref stt,64
 if p3=0 { ; 長さを取得
  ichi=0 : stt=0
  repeat
   peek code,p2,ichi
   if code=0 : break ; EOF
   if code>128 : stt+ : if code<177|(code>223) : ichi+=2 : stt+ : continue ichi ; 半角カナも2バイト
   ichi+ : stt+
   if code=13 : ichi+ : continue ichi ; CR+LF→LF
  loop
 }
 if p3 {
  if p3=-1 : strlen p3,p2
  ichi=0 : stt=0
  repeat p3
   peek code,p2,ichi
   if code=13 : poke p1,stt,10 : ichi+=2 : stt+ : continue ichi ; CR+LF→LF
   if code>128 { ; 2バイト・半角カナ文字
    if code>176&(code<224) { ; 半角カナは2バイトに
     poke p1,stt,142 : poke p1,stt+1,code : stt+
    } else {
     peek code.1,p2,ichi+1 ; 2バイト文字の下位バイト取得
     if code.1<159 {
      if code<160 : poke p1,stt,code*2-97 : else : poke p1,stt,code*2-225
      if code.1>127 : poke p1,stt+1,code.1+96 : else : poke p1,stt+1,code.1+97
     } else {
      if code<160 : poke p1,stt,code*2-96 : else : poke p1,stt,code*2-224
      poke p1,stt+1,code.1+2
     }
     ichI+ : stt+
   }} else { ; 1バイト文字
    poke p1,stt,code
   }
   ichI+ : stt+
  loop
 }
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 sdim buf,32000,2
 sdim file,256
 dialog "txt",16,"S-JIS(ANSI)形式のファイル"
 if stat=0 : end
 file=refstr
 bload file,buf
 to_euc buf.1,buf,-1
 dialog "txt",17,"保存するEUC形式のファイル名"
 if stat=0 : end
 file=refstr
 strmid chk,file,-1,4 ; ファイル名の終端4文字が「.txt」かチェック
 if chk!=".txt" : file+=".txt"
 strlen len,buf.1
 buf=buf.1 ; なぜか変数を移し変えなければS-JIS形式で保存される(謎
 bsave file,buf,len
 dialog"変換完了"

TOPへ戻る

31.EUCからS-JISに変換するモジュール

  Unicodeの相互変換モジュールを作成しようとしましたが中止しました(30参照)。
  ココはUnixで使用されているEUCコードをWindowsので使用されているS-JIS(ANSI)コードに変えるモジュールです。
  使い方はllmod.asのfrom_uni(to_uni)と同じようにしています。
  第3パラメータに変換する文字列の長さを入れます。-1で全て変換、0で全変換に必要なバイト数がstatに返ります。
  気をつけるというかわかりませんが…変換できない文字がいくつかあるようです
  他のソフトでも試してみましたが同じ結果となりましたのでスクリプトが悪いわけではない…と思います(^^;
  何個か挙げておきます「\]^_`abcdefg@ABUV」。

  (例)S-JISに変換

;************ 概要説明 *************
;
; from_euc v1,v2,n3
;
; v1 : 変換したS-JIS文字列を入れる変数
; v2 : S-JISに変換するEUC文字列が入った変数
; n3 : S-JISに変換するEUC文字列の長さ
;
;**********************************
#module "codechange"
#deffunc from_euc val,val,int
 mref p1,24
 mref p2,25
 mref p3,2
 mref stt,64
 if p3<1 { ; 長さを取得
  ichi=0 : stt=0
  repeat
   peek code,p2,ichi
   if code=0 : break ; EOF
   if code>127 : ichi+=2 : if code=142 : stt+ : continue ichi : else : stt+=2 : continue ichi
   if code<128 : ichi+ : stt+ : if code=10 : stt+
  loop
 }
 if p3 {
  if p3=-1 : p3=stt
  ichi=0 : stt=0
  repeat p3
   peek code,p2,ichi
   if code=10 : code.1=13 : poke p1,stt,code.1 : stt+ ; LF→CR+LF
   if code>127 { ; 2バイト・半角カナ文字
    peek code.1,p2,ichi+1 ; 2バイト・半角カナ文字の下位バイト取得
    if code=142 : poke p1,stt,code.1 : ichi+=2 : stt+ : continue ; 半角カナ文字
    if code\2=0 : code.1-=2
    if code\2=1 : code.1-=97 : if code.1>125 : code.1+
    if code<223 : code=code+1/2+48 : else : code=code+1/2+112
    poke p1,stt,code
    poke p1,stt+1,code.1
    ichi+ : stt+
   } else { ; 1バイト文字
    poke p1,stt,code
   }
   ichi+ : stt+
  loop
 }
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 sdim buf,32000,2
 sdim file,256
 dialog "txt",16,"EUC形式のファイル"
 if stat=0 : end
 file=refstr
 bload file,buf
 from_euc buf.1,buf,-1
 mesbox buf.1,640,480,5
 stop

TOPへ戻る

32.小数点以下があっても加算できるモジュール

  以前本家掲示板であった質問に答えたものの修正版です。
  いろいろと修正しましたがまだおかしい箇所がある場合報告いただければ幸いです。
  ホントはもっと短く出来るのでしょうけど私の考えではこれ以上短く出来ませんでした(^^;
  32bit演算は変わりませんので小数部用に桁を多く取れば当然整数部用の桁がその分減ります。
  だいたい9桁(途中計算も含む)に収まるようにすればオーバーフローは大丈夫かと。

  (例)加算

;************ 概要説明 *************
;
; fadd "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1とs2の加算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fadd str,str,int
 mref p1,32
 mref p2,33
 mref p3,2
 mref result,65
 peek mflg.0,p1 : if mflg.0='-' : mflg.0=1 : else : mflg.0=0
 peek mflg.1,p2 : if mflg.1='-' : mflg.1=1 : else : mflg.1=0
 getstr tmp,p1,,'.' : int tmp : intn=tmp
 fltn=0 : strlen len,p1
 if len>strsize : getstr tmp,p1,strsize : strlen len.0,tmp : int tmp : fltn=tmp
 getstr tmp,p2,,'.' : int tmp : intn.1=tmp
 fltn.1=0 : strlen len.1,p2
 if len.1>strsize : getstr tmp,p2,strsize : strlen len.1,tmp : int tmp : fltn.1=tmp
 keta=1
 repeat p3
  keta=keta*10
 loop
 intn=intn*keta : intn.1=intn.1*keta
 repeat 2
  keta=1
  if p3-len.cnt>=0 {
   repeat p3-len.cnt
    keta=keta*10
   loop
   if mflg.cnt : intn.cnt-=fltn.cnt*keta : else : intn.cnt+=fltn.cnt*keta
  } else {
   repeat len.cnt-p3
    keta=keta*10
   loop
   if mflg.cnt : intn.cnt-=fltn.cnt/keta : else : intn.cnt+=fltn/keta
  }
 loop
 tmp=intn+intn.1
 str tmp
 strlen len.2,tmp
 if len.2>p3 : strmid intn,tmp,0,len.2-p3 : strmid fltn,tmp,-1,p3 : else : intn="0" : fltn=tmp
 fltn="0000000000"+fltn : strmid fltn,fltn,-1,p3
 strlen len.2,fltn : tmp=0
 repeat len.2
  peek tmp,fltn,len.2-cnt-1
  if tmp!='0' : strmid fltn,fltn,0,len.2-cnt : break
 loop
 tmp=fltn : int tmp
 if tmp=0 : result=intn : else : result=""+intn+"."+fltn
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 a="5" : b="7.324852"
 fadd a,b,8
 mes ""+a+" + "+b+" = "+refstr
 a="52" : b="9"
 fadd a,b,7
 mes ""+a+" + "+b+" = "+refstr
 a="4321610.03" : b="6000007"
 fadd a,b,2
 mes ""+a+" + "+b+" = "+refstr
 stop

TOPへ戻る

33.小数点以下があっても減算できるモジュール

  32の引き算バージョンです。
  ほぼ同じ処理ですが微妙に違いますので載せておきます。コレもおかしい点があれば報告くださいませ。
  桁数は32と同じく9桁くらいまでにしましょう。32で書き忘れてましたがマイナス値の計算も出来るはずですので。

  (例)減算

;************ 概要説明 *************
;
; fsub "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1からs2の減算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fsub str,str,int
 mref p1,32
 mref p2,33
 mref p3,2
 mref result,65
 peek mflg.0,p1 : if mflg.0='-' : mflg.0=1 : else : mflg.0=0
 peek mflg.1,p2 : if mflg.1='-' : mflg.1=1 : else : mflg.1=0
 getstr tmp,p1,,'.' : int tmp : intn=tmp
 fltn=0 : strlen len,p1
 if len>strsize : getstr tmp,p1,strsize : strlen len.0,tmp : int tmp : fltn=tmp
 getstr tmp,p2,,'.' : int tmp : intn.1=tmp
 fltn.1=0 : strlen len.1,p2
 if len.1>strsize : getstr tmp,p2,strsize : strlen len.1,tmp : int tmp : fltn.1=tmp
 keta=1
 repeat p3
  keta=keta*10
 loop
 intn=intn*keta : intn.1=intn.1*keta
 repeat 2
  keta=1
  if p3-len.cnt>=0 {
   repeat p3-len.cnt
    keta=keta*10
   loop
   if mflg.cnt : intn.cnt-=fltn.cnt*keta : else : intn.cnt+=fltn.cnt*keta
  } else {
   repeat len.cnt-p3
    keta=keta*10
   loop
   if mflg.cnt : intn.cnt-=fltn.cnt/keta : else : intn.cnt+=fltn.cnt/keta
  }
 loop
 tmp=intn-intn.1
 str tmp
 strlen len,tmp
 if len>p3 : strmid intn,tmp,0,len-p3 : strmid fltn,tmp,-1,p3 : else : intn="0" : fltn=tmp
 fltn="0000000000"+fltn : strmid fltn,fltn,-1,p3
 strlen len,fltn : tmp=0
 repeat len
  peek tmp,fltn,len-cnt-1
  if tmp!='0' : strmid fltn,fltn,0,len-cnt : break
 loop
 tmp=fltn : int tmp
 if tmp=0 : result=intn : else : result=""+intn+"."+fltn
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 a="1.23" : b="0.000054321"
 fsub a,b,9
 mes ""+a+" - "+b+" = "+refstr
 a="55" : b="6.004982"
 fsub a,b,7
 mes ""+a+" - "+b+" = "+refstr
 a="149930" : b="821"
 fsub a,b,3
 mes ""+a+" - "+b+" = "+refstr
 stop

TOPへ戻る

34.小数点以下があっても乗算できるモジュール

  一番オーバーフローしやすい演算と思われますので気をつけてください。
  アルゴリズムの改良によりオーバーフローしにくくしました。処理行数も6行縮みました^^
  また0〜1まで極小数値同士の演算も改良して0を除く塊が9桁以内の結果なら例え50桁でもいけるようにしました。

  (例)乗算

;************ 概要説明 *************
;
; fmul "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1とs2の乗算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fmul str,str,int
 mref p1,32
 mref p2,33
 mref p3,2
 mref result,65
 mflg=0
 repeat 2
  if cnt : result=p2 : else : result=p1
  peek mflg.1,result
  if mflg.1='-' : mflg+
  getstr tmp,result,,'.'
  int tmp
  if tmp<0 : intn.cnt=tmp*-1 : else : intn.cnt=tmp
  strlen len.2,result
  if len.2>strsize : strmid tmp,result,strsize,p3 : else : tmp=""
  strlen len.2,tmp
  repeat len.2
   peek keta,tmp,len.2-cnt-1
   if keta!='0' : strmid tmp,tmp,0,len.2-cnt : break
  loop
  keta=tmp
  int keta
  if keta=0 : tmp=""
  strlen len.cnt,tmp
  if cnt : len+len.1
  tmp=""+intn.cnt+""+tmp
  int tmp
  intn.cnt=tmp
 loop
 tmp=intn*intn.1
 str tmp
 strlen len.2,tmp
 if len.2-len>0 : strmid intn,tmp,0,len.2-len : else : repeat len : tmp="0"+tmp : loop : if mflg\2 : intn="-0" : else : intn="0"
 strmid fltn,tmp,-1,len
 strmid fltn,fltn,0,p3
 tmp=fltn : int tmp
 if tmp=0 : result=intn : else : result=""+intn+"."+fltn
 int intn
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 a="0.0000045204" : b="-0.00000000000133"
 fmul a,b,25
 mes ""+a+" × "+b+" = "+refstr
 a="-7.02" : b="0.004982"
 fmul a,b,9
 mes ""+a+" × "+b+" = "+refstr
 a="110730.3" : b="12.05"
 fmul a,b,3
 mes ""+a+" × "+b+" = "+refstr
 stop

TOPへ戻る

35.小数点以下があっても除算できるモジュール

  小数点以下があってもOKな割り算モジュールは整数同士の演算から小数が出る唯一の演算とと言う点から
  他の加減乗算モジュールよりかは需要があるのではないでしょうか。
  今回は初めの演算する数値の桁数、途中の計算での合計桁数が多すぎなければ
  答えとなる数値の桁数が15桁であろうが30桁でも例え1000桁でもいける…はずです(自信なし

  (例)除算

;************ 概要説明 *************
;
; fdiv "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1とs2の除算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fdiv str,str,int
 mref p1,32
 mref p2,33
 mref p3,2
 mref result,65
 mflg=0
 repeat 2
  if cnt : result=p2 : else : result=p1
  peek mflg.1,result
  if mflg.1='-' : mflg+
  getstr tmp,result,,'.'
  int tmp
  if tmp<0 : intn.cnt=tmp*-1 : else : intn.cnt=tmp
  strlen len.2,result
  if len.2>strsize : strmid tmp,result,strsize,p3 : else : tmp=""
  strlen len.2,tmp
  repeat len.2
   peek keta,tmp,len.2-cnt-1
   if keta!='0' : strmid tmp,tmp,0,len.2-cnt : break
  loop
  keta=tmp
  int keta
  if keta=0 : tmp=""
  strlen len.cnt,tmp
  if cnt : len-len.1
  tmp=""+intn.cnt+""+tmp
  int tmp
  intn.cnt=tmp
 loop
 if intn.1=0 : result="error" : return
 if len<0 : repeat len*-1 : intn=intn*10 : loop : len=0
 keta=intn/intn.1
 tmp=""+keta
 if keta<0 : intn=intn*-1
 strlen len.1,tmp
 strmid result,tmp,0,len.1-len
 if mflg\2 : result="-"+result
 if len|(intn\intn.1) : result+="."
 getstr tmp,tmp,len.1-len,''
 result+=tmp
 repeat p3
  intn=intn\intn.1*10
  if intn=0 : break
  keta=intn/intn.1
  result+=""+keta
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 a="-9" : b="4"
 fdiv a,b,3
 mes ""+a+" ÷ "+b+" = "+refstr
 a="3141.59" : b="2.65358"
 fdiv a,b,16
 mes ""+a+" ÷ "+b+" = "+refstr
 a="18.0000600" : b="-0.130"
 fdiv a,b,8
 mes ""+a+" ÷ "+b+" = "+refstr
 stop

TOPへ戻る

36.文章をゆっくり端から表示するモジュール

  試してないので真相は知らないのですが、hspdx.dllを使用してDirectXモードになっている時に
  text命令は使えないというのを昔どこかでみたような記憶があります。
  また、半角カナの入り混じった文章を表示させるときに文字化けが発生してしまうバグが存在します。
  こういったときにご利用ください。
  少々面倒ですが、コレを応用させれば後ろから1文字ずつ表示させることも出来ますよ。

  (例)全角・半角の入り混じった文章を表示させる

;************ 概要説明 *************
;
; msg "s1",n2
;
; s1 : 文字列・文字列型の変数
; n2 : 速度(注.text命令の速度とは異なります)
;
;**********************************
#module "string"
#deffunc msg str,int
 mref txt,32
 mref speed,2
 mref bmscr,67
 fsize=bmscr.32/2
 strlen len,txt
 posx=csrx : posy=csry
 sdim moji,4
 repeat len
  peek tmp,txt,cnt
  poke moji,0,tmp
  if tmp>128&(tmp<160)|(tmp>223) {
   peek tmp,txt,cnt+1
   poke moji,1,tmp
   num=2
  } else {
   poke moji,1,0
   num=1
  }
  pos posx,posy : mes moji
  posx+=fsize*num
  if speed>0 : wait speed
  continue cnt+num
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 pos 30,200
 sdim buf,128
 buf="アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン"
 msg buf,5
 stop

TOPへ戻る

37.グラデーション文字2(モジュール版)

  随分前に画像・音楽編の02にグラデーション文字を表示するTIPSを作成しました。
  白い背景の時には使えたのですが、別の色で塗りつぶされていたり、画像が貼り付けられていた場合はダメでした。
  また、一時ウィンドウ(バッファ)も2つ(計3画面)用意しなければ出来ないというものでした。
  今回は36の1文字ずつ表示させるものの別の使い方として、
  背景が何であろうと使えるようにしたものです。それも1画面ONLYとモジュールで。
  応用が利くようになったのですが、色の変化が最低でも1文字単位なのであまりきれいに変わってくれません。

  (例)グラデーション文章を表示させる

;************ 概要説明 *************
;
; colful "s1",n2,n3
;
; s1 : 文字列・文字列型の変数
; n2 : 開始色(「赤輝度<<16」+「緑輝度<<8」+「青輝度」の形式で指定します)
; n3 : 終了色(「赤輝度<<16」+「緑輝度<<8」+「青輝度」の形式で指定します)
;
;**********************************
#module "string"
#deffunc colful str,int,int
 mref txt,32
 mref start,1
 mref finish,2
 mref bmscr,67
 sdim moji,4
 fsize=bmscr.32/2
 strlen len,txt
 len.1=len-1
 posx=csrx : posy=csry
 red.0=start>>16&$ff : green.0=start>>8&$ff : blue.0=start&$ff ; 開始色
 red.1=finish>>16&$ff : green.1=finish>>8&$ff : blue.1=finish&$ff ; 終了色
 red.2=red.1-red.0/len.1 : green.2=green.1-green.0/len.1 : blue.2=blue.1-blue.0/len.1 ; 1文字ごとの増分値
 color red,green,blue
 repeat len
  peek tmp,txt,cnt
  poke moji,0,tmp
  if tmp>128&(tmp<160)|(tmp>223) {
   peek tmp,txt,cnt+1
   poke moji,1,tmp
   num=2
  } else {
   poke moji,1,0
   num=1
  }
  pos posx,posy : mes moji
  posx+=fsize*num
  color red.2*cnt+red,green.2*cnt+green,blue.2*cnt+blue
  if speed>0 : wait speed
  continue cnt+num
 loop
 return
#global ; ***** ここまでがモジュール ここから下がサンプル *****

 sdim buf,56
 sdim name,20
 picload "hsp2ttl.jpg"
 buf="きれいなグラデーションがかかっているのかな?"
 name="byアルティメット"
 font "",25,1
 col.0=255<<16 : col.1=255<<8
 pos 50,50 : colful buf,col.0,col.1
 col.0=0 : col.1=255<<16+(255<<8)+255
 pos 200,120 : colful name,col.0,col.1
 stop

TOPへ戻る