UWSCという開発ソフトを使って作り上げる作業を実際にやってみるカテゴリ。準備した自作関数や使い方、トラブルを記事にしていきます。得るものがあれば幸いです。
今回は、プログラム中でちょこっと記憶したりするのに便利なフィールドデータを扱う関数です。
今回は、プログラム中でちょこっと記憶したりするのに便利なフィールドデータを扱う関数です。
記事の内容
○フィールドデータの数を返す関数
○フィールドデータの数を返す関数
戻値(int)=nthc(txt,spr)
○指定されたフィールドデータを返す関数
戻値(str)=nthf(txt,spr,n)
以前公開した関数なのですが、セパレータとして1文字しか使用できないという制限があったので修正します。
プログラム中でちょこっとデータを記憶しておきたい場合などフィールドデータを作りたいときがあります。フィールドデータとは以下のようなもの。
フィールドデータ(カンマ区切りのデータなど):tarou,hanako,jirou,pokutaro
このようにデータを整理しておくと扱わないといけない変数を減らせるので便利です。昔使った環境に便利な関数があったのでそれを移植します。(この関数は論理が複雑…というかちょっとややこしいです。)
関数の仕様は
フィールドデータtxt:tarou,hanako,jirou,pokutaro
があったときに、
N=nthc(txt,”,”)とすると、N=4となる(フィールドの数を返してくれる)
T=nthf(txt,”,”,3)とすると、T=”jirou”となる(フィールドの3番目のデータを返してくれる)
があったときに、
N=nthc(txt,”,”)とすると、N=4となる(フィールドの数を返してくれる)
T=nthf(txt,”,”,3)とすると、T=”jirou”となる(フィールドの3番目のデータを返してくれる)
このような関数を作成しようとしています。(あまりに大きなフィールドを渡すとスピードが出ない気もしますが、UWSCですので便利な方がいいかなと思います。)
C言語のstrstr関数を移植
準備としてC言語のstring.hから一つ関数を移植(擬似移植?)。nthc、nthf関数の中からこの関数を呼び出して使用します。(既にCへ移植してあったのでそこからUWSCに引っ張ってきたのでこうしただけ。特に意味はありません。方法は他にもあります。)
1 2 3 4 5 6 7 8 9 10 11 12 | FUNCTION strstr(txt,sch) //txt中にschが無い、txtよりschが長い場合““空白が返される r=““ FOR i=1 TO LENGTH(txt) search=COPY(txt,i,LENGTH(sch)) IF (search=sch) r=COPY(txt,i) BREAK ENDIF NEXT RESULT=r FEND |
1,12行目 | 1 12 | FUNCTION strstr(txt,sch) FEND |
strstr(txt,sch)関数宣言 引数txt中にからschを検索し、sch以降を返す関数。(C言語仕様) | ||
3行目 | 3 | r=““ |
戻り値として使用する変数rの初期化。 | ||
4,10行目 | 4 10 | FOR i=1 TO LENGTH(txt) NEXT |
引数txtを1番目から(文字数)番目までスキャンするためのループ。 | ||
5行目 | 5 | search=COPY(txt,i,LENGTH(sch)) |
変数searchにi番目から(引数schの文字数)個を取り出して代入。 COPY(DT,N1,N2):DTのN1番目の文字からN2個の文字列を返すUWSC標準関数。 | ||
6~9行目 | 6 7 8 9 | IF (search=sch) r=COPY(txt,i) BREAK ENDIF |
もし5行目で代入したsearchと引数schが等しいなら、 変数rに引数txtのi番目から引数txtの最後までを代入。(UWSCのCOPY関数は第3引数を省略すると最後までとなる) BREAKはループを出ろというUWSCの命令。 | ||
11行目 | 11 | RESULT=r |
関数の戻り値として変数rを返す。 |
フィールドの数を返すnthc関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | FUNCTION nthc(txt,spr) n=1 s=txt IF strstr(s,spr)=““ n=0 ELSE WHILE (0=0) s=strstr(s,spr) s=COPY(s,LENGTH(spr)+1) n=n+1 IF strstr(s,spr)=““ BREAK ENDIF WEND ENDIF RESULT=n FEND |
1,17行目 | 1 17 | FUNCTION nthc(txt,spr) FEND |
nthc(txt,spr)関数宣言: 引数txt(フィールドデータ)に引数spr(セパレータ)で区切られたフィールドがいくつあるかを返す関数。 | ||
2,3行目 | 2 3 | n=1 s=txt |
使用する変数の初期化。 変数nはフィールドの数を数えるのに使用。 変数sはフィールドデータを調べるための文字列として使用。 | ||
4,6,15行目 | 4 6 15 | IF strstr(s,spr)=““ ELSE ENDIF |
条件分岐。フィールドデータにセパレータが含まれてないかどうかを調べる。 | ||
5行目 | 5 | n=0 |
○⇒(フィールドデータにセパレータが含まれてない) 変数nに0を代入し、16行目へ。 | ||
7,11~14行目 | 7 11 12 13 14 | WHILE (0=0) IF strstr(s,spr)=““ BREAK ENDIF WEND |
×⇒(フィールドデータにセパレータが含まれている) 8~10行目のループへと突入。 ループ条件を0=0としてあるので、常に成り立ち無限ループとなるが、(WHILE (1)と書く人が多いかも。) BREAK条件を、strstr関数を実行した結果変数sが空白となったとき、として制御する。(8行目を通るたびに変数sは削られていくことに注目。) | ||
8~10行目 | 8 9 10 | s=strstr(s,spr) s=COPY(s,LENGTH(spr)+1) n=n+1 |
この部分を通るたびに1つ後のセパレータの次のデータを先頭に持ってくるためのルーチン。 変数sにstrstr関数の戻り値を代入。 8行目を通るたびに変数sはセパレータを先頭とする文字列に置き換わっていく。 9行目で変数sの先頭にあるセパレータ部分を取り除く。(UWSCのCOPY関数は第3引数を省略すると最後までとなる) 10行目の変数nはフィールドの数をなのでここでインクリメント。 | ||
16行目 | 16 | RESULT=n |
関数の戻り値として変数rを返す。 |
指定したフィールドのデータを返すnthf関数
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 | FUNCTION nthf(txt,spr,n) i=0 tmp=““ nlast=nthc(txt,spr) r=““ IF (n<1) ELSEIF (txt=““) ELSEIF (strstr(txt,spr)=““) ELSEIF (n>nlast) ELSE s=txt WHILE (0=0) tmp=s s=strstr(s,spr) i=i+1 IF (i=n) n1=LENGTH(tmp) n2=LENGTH(s) r=COPY(tmp,1,n1–n2) BREAK ELSE s=COPY(s,LENGTH(spr)+1) ENDIF IF s=““ BREAK ENDIF WEND ENDIF RESULT=r FEND |
1,30行目 | 1 30 | FUNCTION nthf(txt,spr,n) FEND |
nthf(txt,spr,n)関数宣言: 引数spr(セパレータ)で区切られた引数txt(フィールドデータ)から引数n番目のデータを返す関数。 | ||
2~5行目 | 2 3 4 5 | i=0 tmp=““ nlast=nthc(txt,spr) r=““ |
使用する変数の初期化。 変数iはフィールドの数を数えるのに使用。 変数tmpは変数sを退避するため一時的に使用。 変数nlastはフィールドデータの数を代入。 変数rは関数の戻り値を記憶しておくために使用。初期値として空白を入れておく。 | ||
6~10,28行目 | 6 7 8 9 10 28 | IF (n<1) ELSEIF (txt=““) ELSEIF (strstr(txt,spr)=““) ELSEIF (n>nlast) ELSE ENDIF |
条件分岐いろいろ:面倒なので最初に弾ける条件は弾いてしまいます。 5行目で変数rに空白を代入してあるので弾かれた条件ではそのまま29行目で空白を関数の引数として返します。 6行目: 0番目が指定された ⇒戻り値として空白を返す。 7行目: フィールドデータとして空白が渡された ⇒戻り値として空白を返す。 8行目: フィールドデータ中にセパレータが含まれてなかった ⇒戻り値として空白を返す。 9行目: フィールドの数より大きなnを指定された ⇒戻り値として空白を返す。 ×⇒(上記すべて成り立たなかった) 11~27行目を実行。 | ||
11行目 | 11 | s=txt |
使用する変数の初期化。 変数sはフィールドデータを調べるための文字列として使用。初期値は引数txt。 | ||
12,24~27行目 | 12 24 25 26 27 | WHILE (0=0) IF s=““ BREAK ENDIF WEND |
nthc関数の7,11~14行目と同じ条件のループ。(14行目を通るたびに変数sは削られていくことに注目。) | ||
13~15行目 | 13 14 15 | tmp=s s=strstr(s,spr) i=i+1 |
13行目: 変数tmpに変数sを一時的に退避。 14行目: 変数sにstrstr関数の戻り値を代入。 通るたびに変数sはセパレータを先頭とする文字列に置き換わっていく。 15行目: 変数iはフィールドの数をなのでここでインクリメント。 | ||
16~23行目 | 16 17 18 19 20 21 22 23 | IF (i=n) n1=LENGTH(tmp) n2=LENGTH(s) r=COPY(tmp,1,n1–n2) BREAK ELSE s=COPY(s,LENGTH(spr)+1) ENDIF |
条件:もしフィールドの数を数えている変数iと引数として指定された引数nが同じなら、(目的のデータが見つかったなら) ○⇒ 17行目: 退避していた変数tmpの文字数を変数n1に代入。 18行目: 現在の変数sの文字数を変数n2に代入。 19行目: 変数rに目的のフィールドの文字列を代入。 (退避していた変数tmpの1文字目から(n1-n2)個がそれに相当します。) 20行目:見つかったのでループを抜ける。 ×⇒ 22行目: 変数sの(セパレータの文字数+1)番目からの最後までを変数sに代入。 (先頭にあったセパレータを取り除いたものを変数sとして再度13行目のループ先頭へ戻る。) (UWSCのCOPY関数は第3引数を省略すると最後までとなる) | ||
29行目 | 29 | RESULT=r |
関数の戻り値として変数rを返す。 |
動作確認
1 2 3 4 5 6 7 8 9 10 11 | PRINT “nthc kotae =“+nthc(“abc[]defghi[]jklm[]nop“,“[]“) PRINT “nthc kotae =“+nthc(“[]defghi[]jklm[]nop“,“[]“) PRINT “nthc kotae =“+nthc(“abc[]defghi[]jklm[]“,“[]“) PRINT “–––––––––––––––––––––––––––“ FOR i=–1 TO 5 PRINT “nthf kotae “+i+“=“+nthf(“abc[]defghi[]jklm[]nop“,“[]“,i) NEXT PRINT “–––––––––––––––––––––––––––“ FOR i=–1 TO 5 PRINT “nthf kotae “+i+“=“+nthf(“[]defghi[]jklm[]“,“[]“,i) NEXT |
1~3行目 | 1 2 3 | PRINT “nthc kotae =“+nthc(“abc[]defghi[]jklm[]nop“,“[]“) PRINT “nthc kotae =“+nthc(“[]defghi[]jklm[]nop“,“[]“) PRINT “nthc kotae =“+nthc(“abc[]defghi[]jklm[]“,“[]“) |
nthc関数の動作確認です。 セパレータとして”[]“(2文字)を渡したときに、先頭と終端がセパレータではない、先頭がセパレータでである、終端がセパレータであるフィールドデータを渡して正常にカウントするか確認します。 | ||
5~7行目 | 5 6 7 | FOR i=–1 TO 5 PRINT “nthf kotae “+i+“=“+nthf(“abc[]defghi[]jklm[]nop“,“[]“,i) NEXT |
nthf関数の動作確認です。 先頭・終端がセパレータでないフィールドデータを与えたときの挙動を確認します。(n番目の指定は-1~5までやってみます。) | ||
9~11行目 | 9 10 11 | FOR i=–1 TO 5 PRINT “nthf kotae “+i+“=“+nthf(“[]defghi[]jklm[]“,“[]“,i) NEXT |
nthf関数の動作確認(変則なフィールドデータ)です。 先頭・終端がセパレータであるフィールドデータを与えたときの挙動を確認します。(n番目の指定は-1~5までやってみます。) | ||
4,8行目 | 4 8 | PRINT “–––––––––––––––––––––––––––“ PRINT “–––––––––––––––––––––––––––“ |
結果を見やすくするための区切りを表示。 |
nthc kotae =4 nthc kotae =4 nthc kotae =4 ————————— nthf kotae -1= nthf kotae 0= nthf kotae 1=abc nthf kotae 2=defghi nthf kotae 3=jklm nthf kotae 4=nop nthf kotae 5= ————————— nthf kotae -1= nthf kotae 0= nthf kotae 1= nthf kotae 2=defghi nthf kotae 3=jklm nthf kotae 4= nthf kotae 5= |
一応思い通りの仕様の動きができました。
記事の内容は伝わりましたでしょうか。
○フィールドデータの数を返す関数
○フィールドデータの数を返す関数
戻値(int)=nthc(txt,spr)
○指定されたフィールドデータを返す関数
戻値(str)=nthf(txt,spr,n)
コメント