■ Icon > Icon土日夜 はじめに 風つかい 目次 Iconは アリゾナ大学の Icon Projectによって、開発されているテキスト処理 言語です。 Iconは table,set,list,record,等の豊富な data構造と Back trackingを含む 強力な制御構造を備えていますので、テキスト解析に威力を発揮します。 英語の国で開発されている言語ですが、日本語の処理にも不自由しませんので 日本でも、もっともっと 使われてよい言語と思います。 しかし、未だ 日本語の入門書が ありませんので、 AWKについて、ある程度の 知識を お持ちになっている方を 対象として、入門講座を書きました。 ・テキスト解析言語 Icon入門講座 ---AWKerのための Icon入門--- ・Icon日記 ---テキスト解析言語 Icon入門講座2--- ・Icon雑記帳 ---テキスト解析言語 Icon入門講座3--- ・Icon散歩道 ---テキスト解析言語 Icon入門講座4--- この Icon土日夜(どに〜ちょ)は その続編として、その後 作ったプログラムや 前の 講座で書き落とした ものを、まとめたものです。 前の 4編の講座と いっしょに ご覧になって Iconを使って頂けると うれしい です。 Iconのプログラムおよびライブラリーは、次の所から 入手できます。 http://www.cs.arizona.edu/icon/index.html この講座は、主に PCVANのPIGのテキストデータ処理会議室にアップロードした ものに加筆・修正を行ったものです。 Iconは PDSですので、この入門講座も同じ扱いとします。(転載・編集自由) (This textbook is in the public domain.) 目次 はじめに (1) jtrim(1) (2) jtrim(2) (3) jtrim(3) (4) jtrim(4) (5) jtrim(5) (6) AWK風 program(1) (7) AWK風 program(2) (8) AWK風 program(3) (9) AWK風 program(4) (10) AWK風 program(5) (11) AWK風 program(6) (12) AWK風 program(7) (13) AWK風 program(8) (14) AWK風 program(9) (15) record (16) 構造体 tree表示(1) (17) 構造体 tree表示(2) (18) n進数計算 (19) table書き出し (20) table読み込み(1) (21) table読み込み(2) (22) 構造体 copy (23) 引用符 (24) Windows Icon 9.3.1 (25) Icon Newsletter No.54 むすび 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: ECHO / 遊佐未森 (icon400.txt 1998/02/18 PCVAN PIG) ■ Icon > Icon土日夜(1) jtrim(1) 風つかい 目次 はやいもので、Icon入門講座を始めてもう1年になります。昨年の秋に始め た頃は、こんなに書くことがあるとは思っていませんでした。 始めてみますと、結構ネタが出てきまして、未だ当分は続けられそうです。 シリーズにしようと思っていた訳ではないのですが、100Kbyte位に書込みが たまりますと、ひとまず まとめ ということで、libraryに入れています。 4回まとめて、第5回目の始めです。 さて そのサブタイトルですが、 【Icon土日夜】にしました。 【Iconどに〜ちょ】 と読んで下さい。 某電話会社のCMからパクったタイトルです。(汗) 私は、カタギの勤め人ですので、この原稿をいつも、土曜、日曜、平日の夜 に書いているもんで、そのものズバリ。 と、いうわけで今回はこのタイトルにします。 さて、今回は、テキストに含まれる空白の削除 について、少々。 先日、テキストデータ末尾の空白削除をする必要がありました。 日本文では、全角文字の間に、半角文字が結構混在しますので、全角と半角 の spaceを削除しないといけません。 こういう仕事は、sedで簡単・高速に 処理できます。 -----^ TRIM.SED ( date:97-11-29 time:16:07 ) ---------------<cut here #! sed -f #################### # 過剰 space削除 #################### # 日本語対応の sedを使用すること。 # trim.sed 97/11/29 windy comment 追加 # trim.sed 97/08/02 windy 風つかい H.S. # This file is in the public domain. # ↓半角 space3個 s/ +/ /g # 3個以上の半角 spaceは 半角 space2個へ # ↑半角 space2個 # ↓全角 space2個 s/ +/ /g # 全角 spaceの連続は 全角 space1個へ # ↑全角 space1個 s/[ ]+$// # 末尾の半角/全角 spaceを 削除 # ↑半角 spaceと全角 space -----$ TRIM.SED ( lines:16 words:67 ) ----------------------<cut here ・半角 spaceを減らす ・全角 spaceを減らす ・末尾の半角 spaceと全角 spaceの削除 という3つの処理を行いました。 で、これを Iconでやってみようという訳です。 Iconには、trimという末尾の空白を削除する関数があります。 Iconは、英語の国の方が作った言語ですので、空白は、半角 spaceとなって います。 この辺を日本語対応に拡張します。 spaceは表示とか印刷上、半角/全角の判読が不可能です。いちいちコメント を付けていくのもメイドいので 半角 space " " は、"s" に、 全角 space " " は、"□" に と換えて programを作ることにします。 trim.sedは、次のようになります。 -----^ TRIM-.SED ( date:97-11-29 time:16:08 ) --------------<cut here #! sed -f #################### # 過剰 space削除 #################### # 日本語対応の sedを使用すること。 # trim.sedを説明用に、半角" "-> "s", 全角" " -> "□"としたもの # trim-.sed 97/11/29 windy 風つかい H.S. # This file is in the public domain. s/sss+/ss/g # 3個以上の半角 spaceは 半角 space2個へ s/□□+/□/g # 全角 spaceの連続は 全角 space1個へ s/[s□]+$// # 末尾の半角/全角 spaceを 削除 -----$ TRIM-.SED ( lines:11 words:49 ) ---------------------<cut here ところで、全角、半角は英語では何と訳しているのかと思って、 Ken Lundeさんの 日本語情報処理(Understanding Japanese Information Processing)を 見てみまし たら、 全角は、full-width 半角は、half-width と、訳してありました。 全幅、半幅とかに意訳してありますね。 確かに、"角"と言われても分からない ですよね。 "角"って、どこから来たんでしょうね? 漢字は 四角の形が多いので、日本人の私には、全角、半角と聞いても そんなに 違和感は無いのですが。 それではまず、重複 spaceの削除からです。早速 programを。 trim_mという procedureを作ります。 ちょっと汎用化して、n個以上の半角文字ssを m個の ssへ置換する procedureと しました。 -----^ TRIM1.ICN ( date:97-11-29 time:20:14 ) --------------<cut here #################### # trim拡張のテスト #################### # 講座用に、半角 space -> "s",全角 space ->"□"としている。 # trim1.icn 97/11/29 windy 風つかい H.S. # This file is in the public domain. link sjis_e # jimage <-日本語対応 image() procedure main() s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3 := "ssss□□□ss" s4 := "" write("元データ") write("s1: ",jimage(s1)) write("s2: ",jimage(s2)) write("s3: ",jimage(s3)) write("s4: ",jimage(s4)) write("\n2文字以上の 半角 space(の連続)は、半角 space 1個に変換") write("s1: ",jimage(trim_m(s1,"s"))) write("s2: ",jimage(trim_m(s2,"s"))) write("s3: ",jimage(trim_m(s3,"s"))) write("s4: ",jimage(trim_m(s4,"s"))) write("\n3文字以上の 半角 space(の連続)は、半角 space 2個に変換") write("s1: ",jimage(trim_m(s1,"s",3,2))) write("s2: ",jimage(trim_m(s2,"s",3,2))) write("s3: ",jimage(trim_m(s3,"s",3,2))) write("s4: ",jimage(trim_m(s4,"s",3,2))) end #################### # n個以上連続した半角文字を m(<n)個へ圧縮 #################### # trim_m 1997/11/29 windy 風つかい H.S. # arg: s : 変換対象文字列 # ss : 圧縮対象文字(半角)(1文字) # n : 圧縮対象文字数 # m : 圧縮後の文字数 (<m) # This file is in the public domain. procedure trim_m(s,ss,n,m) # default /s := &subject # 指定が無ければ、走査対象 /ss := " " # 指定が無ければ、space /n := 2 ; sn := repl(ss,n) # 指定が無ければ、2 /m := 1 ; sm := repl(ss,m) # 指定が無ければ、1 s1 := "" # 戻り値の初期値 s ? { # sを走査対象として、 # n文字連続した 対象文字の連続 を見つけたら # ↓その位置 +m文字の位置まで の文字列を足しこみ、 while s1 ||:= tab(find(sn)+m) do tab(many(ss)) # ↑走査位置をその後ろの対象文字以外 # の位置まで移動 return s1 ||:= tab(0) # 残りの部分を足し込み } end # find(s) : 走査対象文字列の中の s文字列を探す。findの値は sの先頭位置 # tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分 # の文字列となる。 # 文字列の最後の文字の後ろの位置は、0。よって tab(0)は最後の文字 # の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。 -----$ TRIM1.ICN ( lines:67 words:204 ) --------------------<cut here trim1.exe を動かした結果です。 -----^ TRIM1 ( date:97-11-29 time:20:15 ) ------------------<cut here 元データ s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3: "ssss□□□ss" s4: "" 2文字以上の 半角 space(の連続)は、半角 space 1個に変換 s1: "s□□sあい□うsえおs□sか□□□□きくsけこs□□sz" s2: "zsz□□sあい□うsえおs□sか□□□□きくsけこs□□s" s3: "s□□□s" s4: "" 3文字以上の 半角 space(の連続)は、半角 space 2個に変換 s1: "ss□□ssあい□うssえおs□sか□□□□きくsけこs□□ssz" s2: "zssz□□ssあい□うssえおs□sか□□□□きくsけこs□□ss" s3: "ss□□□ss" s4: "" -----$ TRIM1 ( lines:17 words:35 ) -------------------------<cut here 次回は、全角文字の連続を圧縮する programを作ってみましょう。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Always /篠原美也子 (icon401.txt 1997/11/29 PCVAN PIG) ■ Icon > Icon土日夜(2) jtrim(2) 風つかい 目次 秋になると、なんとなく「枯葉」(Autumn Leaves)なんかを聞きたくなりますが、 Jazzのアップテンポで聞く「枯葉」は、つむじ風の中を舞う枯葉かな〜 なんぞと 思いながら、さて重複文字の圧縮の続きです。 前回、同じ半角文字の連なりをやりましたが、今回は、全角文字です。 jtrim_mzという procedureを作ります。考え方は前回の trim_mと同じですが 同じ文字の n文字の連続を検出した後に、別の文字の位置へ移動するのに細工が 必要です。 半角文字なら manyで 移動できましたが、全角文字には相当する関数 がありません。 SJIS対応の jmanyという関数を以前作っていますが、これは相当重い procedure なので、全角文字専用ということで、ここでは matchを繰り返し使って相当処理を 行っています。 -----^ TRIM2.ICN ( date:97-11-29 time:22:53 ) --------------<cut here #################### # trim拡張のテスト #################### # 講座用に、半角 space -> "s",全角 space ->"□"としている。 # trim2.icn 97/11/29 windy 風つかい H.S. # This file is in the public domain. link sjis_e # jimage <-日本語対応 image() procedure main() s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3 := "ssss□□□ss" s4 := "" write("元データ") write("s1: ",jimage(s1)) write("s2: ",jimage(s2)) write("s3: ",jimage(s3)) write("s4: ",jimage(s4)) write("\n2文字以上の 全角 space(の連続)は、全角 space 1個に変換") write("s1: ",jimage(jtrim_mz(s1,"□"))) write("s2: ",jimage(jtrim_mz(s2,"□"))) write("s3: ",jimage(jtrim_mz(s3,"□"))) write("s4: ",jimage(jtrim_mz(s4,"□"))) write("\n3文字以上の 全角 space(の連続)は、全角 space 2個に変換") write("s1: ",jimage(jtrim_mz(s1,"□",3,2))) write("s2: ",jimage(jtrim_mz(s2,"□",3,2))) write("s3: ",jimage(jtrim_mz(s3,"□",3,2))) write("s4: ",jimage(jtrim_mz(s4,"□",3,2))) end #################### # n個以上連続した全角文字を m(<n)個へ圧縮 #################### # jtrim_mz 1997/11/29 windy 風つかい H.S. # arg: s : 変換対象文字列 # ss : 圧縮対象文字(全角)(1文字) # n : 圧縮対象文字数 # m : 圧縮後の文字数 (<m) # This file is in the public domain. procedure jtrim_mz(s,ss,n,m) # default /s := &subject # 指定が無ければ、走査対象 /ss := " " # 指定が無ければ、全角 space /n := 2 ; sn := repl(ss,n) # 指定が無ければ、2 /m := 1 # 指定が無ければ、1 s1 := "" # 戻り値の初期値 s ? { # sを走査対象として、 # n文字連続した 対象文字の連続 を見つけたら # ↓その位置 +(m*2)文字の位置まで の文字列を足しこみ、 while s1 ||:= tab(find(sn)+(m*2)) do { while tab(match(ss)) # ↑走査位置を その後ろの対象文字以外の 位置まで 移動 } return s1 ||:= tab(0) # 残りの部分を足し込み } end # match(s): 現在走査位置から、走査対象文字列と s文字列が一致しているか # 判定。 一致すれば、matchの値は一致文字列の次の位置となる。 # find(s) : 現在走査位置以降で、走査対象文字列の中の s文字列を探す。 # 見つかれば、findの値は sの先頭位置となる。 # tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分 # の文字列となる。 # 文字列の最後の文字の後ろの位置は、0。よって tab(0)は最後の文字 # の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。 -----$ TRIM2.ICN ( lines:71 words:213 ) --------------------<cut here 前回の trim1.icnで余計なことをしていましたね。 smという文字列を作った んですが、結局使っていませんでした。(汗) trim2.exeの結果です。 -----^ TRIM2 ( date:97-11-29 time:22:53 ) ------------------<cut here 元データ s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3: "ssss□□□ss" s4: "" 2文字以上の 全角 space(の連続)は、全角 space 1個に変換 s1: "ssss□ssあい□うssssえおs□sか□きくsけこs□sssz" s2: "zssz□ssあい□うssssえおs□sか□きくsけこs□ssss" s3: "ssss□ss" s4: "" 3文字以上の 全角 space(の連続)は、全角 space 2個に変換 s1: "ssss□□ssあい□うssssえおs□sか□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□きくsけこs□□ssss" s3: "ssss□□ss" s4: "" -----$ TRIM2 ( lines:17 words:35 ) -------------------------<cut here 次回は、文字列末尾の space削除をやります。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Autumn Leaves / Wynton Kelly (icon402.txt 1997/11/29 PCVAN PIG) ■ Icon > Icon土日夜(3) jtrim(3) 風つかい 目次 今日は、雨で星は見えないのですが、近ごろは夕暮れになると、南天に木星と 金星がひときわ明るく見えます。少々曇っていても見えますね。あと土星と火星 も見えるんだそうですが、どれがどれかよく分かりません。 さて、今回は、文字列末尾の space削除です。 でも、その前に文字列先頭の space削除をやった方が、分かりやすいので先にやります。 早速 programです。 jtrim_lという procedureを作ります。Test programでは 都合で、jtrim_l1という名前にしています。 -----^ TRIM3.ICN ( date:97-11-30 time:02:15 ) --------------<cut here #################### # trim拡張のテスト #################### # 講座用に、半角 space -> "s",全角 space ->"□"としている。 # trim3.icn 97/11/30 windy 風つかい H.S. # This file is in the public domain. link sjis_e # jimage <-日本語対応 image() 入門講座3(18)参照 procedure main() s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3 := "ssss□□□ss" s4 := "" write("元データ") write("s1: ",jimage(s1)) write("s2: ",jimage(s2)) write("s3: ",jimage(s3)) write("s4: ",jimage(s4)) write("\n先頭の 全角/半角 spaceを削除") write("s1: ",jimage(jtrim_l1(s1,"s","□"))) write("s2: ",jimage(jtrim_l1(s2,"s","□"))) write("s3: ",jimage(jtrim_l1(s3,"s","□"))) write("s4: ",jimage(jtrim_l1(s4,"s","□"))) end #################### # 先頭の半角スペース、全角スペースを取り去る #################### # jtrim_l1 1997/11/30 windy 風つかい H.S. # arg: s : 変換対象文字列 # s1 : 削除対象文字 # s2 : 削除対象文字 # 注意 : s1,s2は、指定しないこと。 Shift-JISの 全角/半角 spaceでは # 2バイト目に "\x20"が来ること や 1バイト目に "\x40"が来ること # は無いので問題ない。その他の文字では保証されない。 # delete leading spaces procedure jtrim_l1(s,s1,s2) /s := &subject /s1 := " " # "\x20" 半角 space /s2 := " " # "\x81\x40" 全角 space s ? { # 走査対象を sとして、 while tab(match(s1 | s2)) # spaceだったら、走査位置を、その次の文字へ # 移動し続ける。 space以外に到着すると失敗して # 走査位置は space以外の文字の先頭になっている。 return tab(0) # space以外の文字から末尾まで } end # match(s): 現在走査位置から、走査対象文字列と s文字列が一致しているか # 判定。 一致すれば、matchの値は一致文字列の次の位置となる。 # tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分 # の文字列となる。 # 文字列の最後の文字の後ろの位置は、0。よって tab(0)は最後の文字 # の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。 -----$ TRIM3.ICN ( lines:58 words:171 ) --------------------<cut here trim3.exeの結果です。 -----^ TRIM3 ( date:97-11-30 time:02:16 ) ------------------<cut here 元データ s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3: "ssss□□□ss" s4: "" 先頭の 全角/半角 spaceを削除 s1: "あい□うssssえおs□sか□□□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3: "" s4: "" -----$ TRIM3 ( lines:11 words:20 ) -------------------------<cut here で、末尾の space削除はどうするかと言うと、末尾から同じ処理をやれば 良いということになります。 早速 programです。 jtrim_tという procedureを作ります。Test programでは、都合で、jtrim_t1 という名前にしています。 末尾から逆方向に走査するのは面倒なので、文字列を反転しておいて順方向 に走査して処理します。 -----^ TRIM4.ICN ( date:97-11-30 time:02:17 ) --------------<cut here #################### # trim拡張のテスト #################### # 講座用に、半角 space -> "s",全角 space ->"□"としている。 # trim4.icn 97/11/30 windy 風つかい H.S. # This file is in the public domain. link sjis_e # jimage <-日本語対応 image() 入門講座3(18)参照 procedure main() s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3 := "ssss□□□ss" s4 := "" write("元データ") write("s1: ",jimage(s1)) write("s2: ",jimage(s2)) write("s3: ",jimage(s3)) write("s4: ",jimage(s4)) write("\n末尾の 全角/半角 spaceを削除") write("s1: ",jimage(jtrim_t1(s1,"s","□"))) write("s2: ",jimage(jtrim_t1(s2,"s","□"))) write("s3: ",jimage(jtrim_t1(s3,"s","□"))) write("s4: ",jimage(jtrim_t1(s4,"s","□"))) end #################### # 末尾の半角スペース、全角スペースを取り去る #################### # jtrim_t1 1997/11/30 windy 風つかい H.S. # arg: s : 変換対象文字列 # s1 : 削除対象文字 # s2 : 削除対象文字 # 注意 : s1,s2は、指定しないこと。 Shift-JISの 全角/半角 spaceでは # 2バイト目に "\x20"が来ること や 1バイト目に "\x40"が来ること # は無いので問題ない。その他の文字では保証されない。 # delete trailing spaces procedure jtrim_t1(s,s1,s2) /s := &subject /s1 := " " # "\x20" 半角 space /s2 := "□" # "\x81\x40" 全角 space s3 := reverse(s1) s4 := reverse(s2) reverse(s) ? { # 走査対象を sの反転文字列として、 while tab(match(s3 | s4)) # 半角 spaceか、全角spaceの反転文字だったら、 # 走査位置を、その次の文字へ移動し続ける。 # その他の文字に到着すると失敗する。 # 走査位置は その他の文字の先頭になっている。 return reverse(tab(0)) # 反転文字列の「その他文字から末尾まで」の # 反転文字列 →すなわち、先頭から 末尾 space } # の手前までの文字列 end # reverse(s) : 文字列 sの反転文字列 # match(s) : 現在走査位置から、走査対象文字列と s文字列が一致しているか # 判定。 一致すれば、matchの値は一致文字列の次の位置となる。 # tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分 # の文字列となる。 # 文字列の最後の文字の後ろの位置は、0。 よって tab(0)は最後の # 文字の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。 -----$ TRIM4.ICN ( lines:64 words:193 ) --------------------<cut here trim4.exeの結果です。 -----^ TRIM4 ( date:97-11-30 time:02:18 ) ------------------<cut here 元データ s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss" s3: "ssss□□□ss" s4: "" 末尾の 全角/半角 spaceを削除 s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz" s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこ" s3: "" s4: "" -----$ TRIM4 ( lines:11 words:20 ) -------------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: The Cat / Jimmy Smith (icon403.txt 1997/11/30 PCVAN PIG) ■ Icon > Icon土日夜(4) jtrim(4) 風つかい 目次 あと、2時間程で、今年も師走になります。今年も、もう残りひと月と思うか、 未だひと月もあると思うか。とりあえず、ひと月あれば、【Iconどに〜ちょ】は まとまりそうな気がします。 さて、jtrim(1)〜(3)の programを まとめて、 jtrimという programに しようと思います。 しかし、いつも同じような filterの programを作っていま すので、共通にできそうな部分をまとめた procedureを作っておこうと思いたち ました。 で、できたのが次の procedureです。 file読込み・書出し、拡張子判定、モニター表示のあたりをまとめています。 -----^ FILT_PAT.ICN ( date:97-11-30 time:22:00 ) -----------<cut here #################### # filter programの雛形 #################### # 1行データ処理 procedureから呼んで filter programを作成する # filt_pat.icn Rev.02 1997/11/30 windy 引数拡張 # filt_pat.icn Rev.01 1997/11/06 windy 風つかい H.S. # arg : args : command line引数を引き継ぐ # args[1]は input.file名 と想定 # wild cardsは未対応 # filt_proc : filter programの1行文処理 procedure # Usage_main: "Usage: 実行file名 " に引き続く message # out_ext : output.fileの拡張子名(指定しなければ標準出力) # in_ext : input.fileの拡張子名 # neg : input.fileの拡張子名チェックを反転 # This file is in the public domain. link string_e, # pre_char #入門講座4 Icon迷い道(5)参照 file_e # f_name #入門講座4 Icon回り道(4)の exe_nameと同じもの # check_ext #入門講座4 Icon迷い道(6)参照 procedure filt_pat(args,filt_proc,Usage_main,out_ext,in_ext,neg) /Usage_main := "input.file" Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成 if *args > 0 then { if args[1] == ("/?" | "-?") then stop(Usage) # Usage出力 else { filename := map(args[1]) # 第1引数を input.file名とみなす if \in_ext then { # 入力拡張子指定があれば、 # input.fileの拡張子チェック check_ext(in_ext,filename,neg) | stop("input.file name error : ",filename) } # input.file open in_dir := open(filename) | stop("cannot open input.file : ",filename) if \out_ext then { # 出力拡張子指定があれば、 out_ext := map(out_ext) line_no := 0 # 行No 動作状態 monitor用 # output.file open # output.file名作成 f_new := (pre_char(filename) || "." || out_ext) out_dir := open(f_new,"a") | { # append modeで open close(in_dir) stop("cannot open output.file : ",f_new) } write(&errout,filename," -> ",f_new) # 動作モニター } } } # 1行づつ input.fileから読み込んで、指定 procedureで処理をして # output.fileに書き出す。 while write(out_dir,filt_proc(read(in_dir))) do { if (\out_ext & (*args >0)) then writes(&errout," ",right(line_no +:= 1,4)) # monitor表示 } if (\out_ext & (*args >0)) then { close(in_dir) # input.file close close(out_dir) # output.file close write(&errout) # monitor表示 カーサー戻し } end -----$ FILT_PAT.ICN ( lines:61 words:252 ) -----------------<cut here この雛形の procedureを使った sampleです。 -----^ TEST404A.ICN ( date:97-11-30 time:22:01 ) -----------<cut here #################### # filt_pat の Test program #################### # 入力ファイルの行頭に行番号を付けるだけの program # test404.icn Rev.01 1997/11/30 windy 風つかい H.S. # This file is in the public domain. link filt_pat procedure main(args) filt_pat(args,add_no) # 引数 : args,proc ,Usage,out_ext,in_ext,neg end procedure add_no(line) static line_no # static宣言 initial { line_no := 0 } # 最初に呼ばれた時にだけ実行 return right(line_no +:= 1,4) || " " || line # 行番号を付加 end -----$ TEST404A.ICN ( lines:19 words:62 ) ------------------<cut here 動きがちょっとメンドイので、test404aと filt_patの関係を図にしておきます。 (用途に応じて作成) (汎用 procedure) - test404a ----------- -- filt_pat ----------- | main() | | | | filter procを呼ぶ | | | | ------------------->------->-----> file読み込み | | | | filt_pat() | | | | 入出力 file open | | | | 入力 file1行読込み| | -------------------- | | | | 行番号付加 proc<-------<-------<---------- 1行 filter proc| | add_no() | | を呼ぶ | | ----------------->------->----------> 加工後 data | | | | | | | | 出力 fileへ書出し | | | | (file末尾迄 繰返し)| | | | 入出力 file close | ---------------------- ----------------------- 念のため結果を確認しておきます。 test404a < trim.sed > test404a とした時の結果です。 -----^ TEST404A ( date:97-11-30 time:22:02 ) ---------------<cut here 1 #! sed -f 2 #################### 3 # 過剰 space削除 4 #################### 5 # 日本語対応の sedを使用すること。 6 # trim.sed 97/11/29 windy comment 追加 7 # trim.sed 97/08/02 windy 風つかい H.S. 8 # This file is in the public domain. 9 # ↓半角 space3個 10 s/ +/ /g # 3個以上の半角 spaceは 半角 space2個へ 11 # ↑半角 space2個 12 # ↓全角 space2個 13 s/ +/ /g # 全角 spaceの連続は 全角 space1個へ 14 # ↑全角 space1個 15 s/[ ]+$// # 末尾の半角/全角 spaceを 削除 16 # ↑半角 spaceと全角 space -----$ TEST404A ( lines:16 words:83 ) ----------------------<cut here 次回は、jtrimをまとめます。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 海になりたい青 / 篠原美也子 (icon404.txt 1997/11/30 PCVAN PIG) ■ Icon > Icon土日夜(5) jtrim(5) 風つかい 目次 今回は、jtrimのまとめです。前回作った filter program用 雛形 procedureの filt_patを使って、まとめています。 jtrim_t1はミスがありましたので、修正し ました。 -----^ TRIM5.ICN ( date:97-11-30 time:22:47 ) --------------<cut here #################### # 重複 spaceを圧縮/末尾 spaceを削除 #################### # 講座用に、半角 space -> "s",全角 space ->"□"としている。 # trim5.icn 1997/11/30 windy 風つかい H.S. # This file is in the public domain. link filt_pat # filt_pat # filter programの雛形 procedure main(args) filt_pat(args,jtrim, ,"trm" ) #引数 -> args,proc ,Usage,out_ext,in_ext,neg end #################### # 重複 spaceを圧縮/末尾 spaceを削除 の1行分処理 procedure #################### procedure jtrim(s) s1 := trim_m1(s,"s",3,2) # 半角 space圧縮 s2 := jtrim_mz(s1,"□") # 全角 space圧縮 s3 := jtrim_t1(s2,"s","□") # 末尾 space削除 return s3 end #################### # n個以上連続した半角文字を m(<n)個へ圧縮 #################### # trim_m1 1997/11/30 windy linkの都合上 名前変更 # trim_m 1997/11/29 windy 風つかい H.S. # arg: s : 変換対象文字列 # ss : 圧縮対象文字(半角)(1文字) # n : 圧縮対象文字数 # m : 圧縮後の文字数 (<m) # This file is in the public domain. procedure trim_m1(s,ss,n,m) # default /s := &subject # 指定が無ければ、走査対象 /ss := " " # 指定が無ければ、space /n := 2 ; sn := repl(ss,n) # 指定が無ければ、2 /m := 1 ; sm := repl(ss,m) # 指定が無ければ、1 s1 := "" # 戻り値の初期値 s ? { # sを走査対象として、 # n文字連続した 対象文字の連続 を見つけたら # ↓その位置 +m文字の位置まで の文字列を足しこみ、 while s1 ||:= tab(find(sn)+m) do tab(many(ss)) # ↑走査位置をその後ろの対象文字以外 # の位置まで移動 return s1 ||:= tab(0) # 残りの部分を足し込み } end #################### # n個以上連続した全角文字を m(<n)個へ圧縮 #################### # jtrim_mz 1997/11/29 windy 風つかい H.S. # arg: s : 変換対象文字列 # ss : 圧縮対象文字(全角)(1文字) # n : 圧縮対象文字数 # m : 圧縮後の文字数 (<m) # This file is in the public domain. procedure jtrim_mz(s,ss,n,m) # default /s := &subject # 指定が無ければ、走査対象 /ss := " " # 指定が無ければ、全角 space /n := 2 ; sn := repl(ss,n) # 指定が無ければ、2 /m := 1 # 指定が無ければ、1 s1 := "" # 戻り値の初期値 s ? { # sを走査対象として、 # n文字連続した 対象文字の連続 を見つけたら # ↓その位置 +(m*2)文字の位置まで の文字列を足しこみ、 while s1 ||:= tab(find(sn)+(m*2)) do { while tab(match(ss)) # ↑走査位置を その後ろの対象文字以外の 位置まで 移動 } return s1 ||:= tab(0) # 残りの部分を足し込み } end #################### # 末尾の半角スペース、全角スペースを取り去る #################### # jtrim_t1 Rev.02 1997/11/30 windy /s2 := "□" -> " " # jtrim_t1 Rev.01 1997/11/30 windy 風つかい H.S. # arg: s : 変換対象文字列 # s1 : 削除対象文字 # s2 : 削除対象文字 # 注意 : s1,s2は、指定しないこと。 Shift-JISの 全角/半角 spaceでは # 2バイト目に "\x20"が来ること や 1バイト目に "\x40"が来ること # は無いので問題ない。その他の文字では保証されない。 # delete trailing spaces procedure jtrim_t1(s,s1,s2) /s := &subject /s1 := " " # "\x20" 半角 space /s2 := " " # "\x81\x40" 全角 space Rev.02 s3 := reverse(s1) s4 := reverse(s2) reverse(s) ? { # 走査対象を sの反転文字列として、 while tab(match(s3 | s4)) # 半角 spaceか、全角spaceの反転文字だったら、 # 走査位置を、その次の文字へ移動し続ける。 # その他の文字に到着すると失敗する。 # 走査位置は その他の文字の先頭になっている。 return reverse(tab(0)) # 反転文字列の「その他文字から末尾まで」の # 反転文字列 →すなわち、先頭から 末尾 space } # の手前までの文字列 end # reverse(s) : 文字列 sの反転文字列 # match(s) : 現在走査位置から、走査対象文字列と s文字列が一致しているか # 判定。 一致すれば、matchの値は一致文字列の次の位置となる。 # find(s) : 現在走査位置以降で、走査対象文字列の中の s文字列を探す。 # 見つかれば、findの値は sの先頭位置となる。 # tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分 # の文字列となる。 # 文字列の最後の文字の後ろの位置は、0。 よって tab(0)は最後の # 文字の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。 -----$ TRIM5.ICN ( lines:124 words:441 ) -------------------<cut here この programに trim5 < trim5.dat として、次のデータを食わせると、 -----^ TRIM5.DAT ( date:97-11-30 time:17:14 ) --------------<cut here ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss ssss□□□ss -----$ TRIM5.DAT ( lines:4 words:3 ) -----------------------<cut here こんな結果となります。 -----^ TRIM5.TRM ( date:97-11-30 time:22:04 ) --------------<cut here ss□ssあい□うssえおs□sか□きくsけこs□ssz zssz□ssあい□うssえおs□sか□きくsけこ -----$ TRIM5.TRM ( lines:4 words:2 ) -----------------------<cut here というところで、jtrim関係は、ここらへんでおしまいにします。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 満たされた月 / 篠原美也子 (icon405.txt 1997/11/30 PCVAN PIG) ■ Icon > Icon土日夜(6) AWK風 program(1) 風つかい 目次 寒い〜。先週から結構寒くなってきました。キーボードを打つ手が凍えると いう程ではないですが、夜の原稿書きは、ついつい酔っぱらいタイピングが多 くなります。 さて、filter programの 雛形 procedureを 紹介しましたが、これを使うと AWKに近い構成の programが書けます。 そこで、殆ど AWKという構成のための procedureを考えてみました。 1行毎の処理の部分はできていますので、あとは ・組み込み変数 ・BEGIN,END が、あれば大体似た構成にできますね。 と言うわけで、早速。 BEGIN, ENDは、存在するとは限りませんので、存在するかどうかのチェック \BEGIN, \END をやっています。 \filt_proc チェックを入れると、BEGINだけ とか ENDだけの programもサポートできます が、それはもう filterじゃない だろう(笑) ということで、はしょってあります。 -----^ FILT_PA4.ICN ( date:97-12-14 time:23:21 ) -----------<cut here #################### # filter programの雛形 #################### # 1行データ処理 procedureから呼んで AWK風 filter programを作成する # filt_patに、AWKにならって、FNR,ARGS,FILENAME,BEGIN,END を追加したもの。 # filt_pa4.icn Rev.02 1997/12/14 windy AWK風 global変数を追加 # filt_pa4.icn Rev.01 1997/12/02 windy 風つかい H.S. # arg : ARGS : command line引数を引き継ぐ # ARGS[1]は input.file名 と想定 # wild cardsは未対応 # filt_proc : filter programの1行文処理 procedure # Usage_main: "Usage: 実行file名 " に引き続く message # out_ext : output.fileの拡張子名(指定しなければ標準出力) # in_ext : input.fileの拡張子名 # neg : input.fileの拡張子名チェックを反転 # This file is in the public domain. global FNR, ARGS, FILENAME, BEGIN, END link string_e, # pre_char #入門講座4 Icon迷い道(5)参照 file_e # f_name #入門講座4 Icon回り道(4)の exe_nameと同じもの # check_ext #入門講座4 Icon迷い道(6)参照 procedure filt_pat(ARGS,filt_proc,Usage_main,out_ext,in_ext,neg) /Usage_main := "input.file" Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成 if *ARGS > 0 then { if ARGS[1] == ("/?" | "-?") then stop(Usage) # Usage出力 else { FILENAME := map(ARGS[1]) # 第1引数を input.file名とみなす if \in_ext then { # 入力拡張子指定があれば、 # input.fileの拡張子チェック check_ext(in_ext,FILENAME,neg) | stop("input.file name error : ",FILENAME) } # input.file open in_dir := open(FILENAME) | stop("cannot open input.file : ",FILENAME) if \out_ext then { # 出力拡張子指定があれば、 out_ext := map(out_ext) line_no := 0 # 行No 動作状態 monitor用 # output.file open # output.file名作成 f_new := (pre_char(FILENAME) || "." || out_ext) out_dir := open(f_new,"a") | { # append modeで open close(in_dir) stop("cannot open output.file : ",f_new) } write(&errout,FILENAME," -> ",f_new) # 動作モニター } } } ################## # BEGIN 節 ################## if \BEGIN then BEGIN() # BEGINが存在すれば、BEGIN()を実行 ################## # MAIN ################## # 1行づつ input.fileから読み込んで、指定 procedureで処理をして # output.fileに書き出す。 FNR := 0 while line := read(in_dir) do { # ある行で、filt_procが失敗しても残り FNR +:= 1 # の行の処理が行われるように、いったん if (\out_ext & (*ARGS >0)) # 行を lineにセット。 then writes(&errout," ",right(FNR +:= 1,4)) # monitor表示 write(out_dir,filt_proc(line)) # filt_procが失敗してもこの行だけ失敗 } if (\out_ext & (*ARGS >0)) then { close(in_dir) # input.file close close(out_dir) # output.file close write(&errout) # monitor表示 カーサー戻し } ################## # END 節 ################## if \END then END() # ENDが存在すれば、END()を実行 end -----$ FILT_PA4.ICN ( lines:80 words:307 ) -----------------<cut here サンプル programです。指定 fileの先頭20行に、行番号を付加して出力 するものです。 -----^ TEST406E.ICN ( date:97-12-15 time:00:49 ) -----------<cut here #################### # filt_pa4 の Test program #################### # 入力ファイルの行頭に行番号を付けて出力する program # test406e.icn Rev.01 1997/12/14 windy 風つかい H.S. # This file is in the public domain. link filt_pa4 procedure main(ARGS) filt_pat(ARGS,add_no) # 引数 : ARGS, filt_proc, Usage_main, out_ext, in_ext, neg # ARGS, FNR, FILENAME, BEGIN, END は global変数(filt_pa4にて宣言) end #################### # BEGIN 節 #################### procedure BEGIN() # 開始メッセージ出力、初期設定などを行う。 filt_patで使う変数は # global宣言すること。 write(&errout,"始めで〜す。") write("----- ",FILENAME) end #################### # 1行毎の処理 (filt_patの1行読込み毎に呼ばれる) #################### # FNR は、行番号 # 5行おきに4桁の行番号、それ以外は行番号の1位を付加 # 20行迄 procedure add_no(line) if FNR > 20 then return &fail # if FNR > 20 then return # これだと、20行以降は空行出力となる。 return ( if (FNR % 5) =0 then right(FNR,4) else " " || FNR[-1] ) || " " || line end #################### # END 節 #################### procedure END() # 終了処理(例:総計出力とか)、終了メッセージ出力などを行う。 write("-----") write(&errout,"終わりで〜す。") end -----$ TEST406E.ICN ( lines:45 words:127 ) -----------------<cut here 動きがちょっとメンドイので、test406eと filt_pa4の関係を図にしておきます。 (用途に応じて作成) (汎用 procedure) - test406e ----------- -- filt_pa4 ----------- | main() | | | | filter procを呼ぶ | | | | ------------------->------->-----> file読み込み | | | | filt_pat() | | | | 入出力 file open | | | | 入力 file1行読込み| | -------------------- | | | | 開始 proc <--------<-------<---------- 開始処理 procを | | BEGIN() | | を呼ぶ | | ----------------->------->----------> | | -------------------- | | | | 1行処理 proc <--------<-------<---------- 1行処理 procを | | add_no() | | を呼ぶ | | ----------------->------->----------> | | | | 出力 fileへ書出し | | | | (file末尾迄 繰返し)| | -------------------- | | | | 終了 proc <--------<-------<---------- 終了処理 procを | | END() | | を呼ぶ | | ----------------->------->----------> | | | | 入出力 file close | ---------------------- ----------------------- test406e test406e.icn > test406e とした時の結果です。 -----^ TEST406E ( date:97-12-15 time:00:49 ) ---------------<cut here ----- test406e.icn 1 #################### 2 # filt_pa4 の Test program 3 #################### 4 # 入力ファイルの行頭に行番号を付けて出力する program 5 # test406e.icn Rev.01 1997/12/14 windy 風つかい H.S. 6 # This file is in the public domain. 7 link filt_pa4 8 9 procedure main(ARGS) 10 filt_pat(ARGS,add_no) 1 # 引数 : ARGS, filt_proc, Usage_main, out_ext, in_ext, neg 2 # ARGS, FNR, FILENAME, BEGIN, END は global変数(filt_pa4にて宣言) 3 end 4 15 #################### 6 # BEGIN 節 7 #################### 8 procedure BEGIN() 9 # 開始メッセージ出力、初期設定などを行う。 filt_patで使う変数は 20 # global宣言すること。 ----- -----$ TEST406E ( lines:22 words:83 ) ----------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: A&M Songs of Burt Bacharack BGD: あんず酒 (icon406.txt 1997/12/15 PCVAN PIG) ■ Icon > Icon土日夜(7) AWK風 program(2) 風つかい 目次 今回も AWK風 programの続きです。 前回のものに更に、定義 fileの読み込み処理 を追加してみました。 時々使っている programを題材にします。 表形式の text dataを、ちょっとだけ いじりたい時に使います。 1文字分印刷の際にはみ出るので spaceを削ろうとか、 欄の間が狭いので、1文字分だけ spaceを追加しようというような場合です。 こんな定義 fileを使います。 -----^ FORMAT.INI ( date:97-12-15 time:23:56 ) -------------<cut here # 【format処理定義】 # d 削除文字 # m 出力時、前にスペースを入れる # a 出力時、後にスペースを入れる # 【処理サンプル】 # d d m dm da md ma ad am ddd #abcdefghijklmnopqrstuvwxyz0123456abcde <- 使用前 #abdegh ijk mnoq rs tv wx yz0 23 456de <- 使用後 sam= d d m dm da md ma ad am ddd #abcdefghijklmnopqrstuvwxyz0123456abcde dat= ddd a a dd mmm -----$ FORMAT.INI ( lines:11 words:56 ) --------------------<cut here で、programです。やっていることは、入門講座4の TB2CSVをほぼ同じです。 定義 fileの読み込みは filter雛形 procedureの方でやって、こちらで解析し ています。 -----^ FORMAT.ICN ( date:97-12-16 time:00:32 ) -------------<cut here #################### # 表形式データ整形 #################### # 表形式 text dataの欄を整形する。1字分 spaceを追加したり、データの1部 # を削除するもの。 # 【処理定義】 format.iniにて。 # d 削除文字 # m 出力時、前にスペースを入れる # a 出力時、後にスペースを入れる # 【処理サンプル】 # d d m dm da md ma ad am ddd #abcdefghijklmnopqrstuvwxyz0123456abcde <- 使用前 #abdegh ijk mnoq rs tv wx yz0 23 456de <- 使用後 # # format.icn Rev.01 97/12/15 windy filter procedureを使用 # form.icn Rev.01 96/09/23 windy 風つかい H.S. # This file is in the public domain. global form link string_e, # cp_split # Icon入門講座4 Icon迷い道(8)参照 file_e, # key_check # Icon入門講座4 Icon迷い道(3)参照 filt_pa5 procedure main(ARGS) filt_pat(ARGS,format2) # 引数 : ARGS, filt_proc, Usage_main, out_ext, in_ext, neg # ARGS, FNR, FILENAME, BEGIN, END, INI は global変数(filt_pa5にて宣言) end #################### # BEGIN 節 #################### procedure BEGIN() # 開始メッセージ出力、初期設定などを行う。 filt_patで使う変数は # global宣言すること。 \INI | stop("no .INI file") # <-INIが無ければエラー form := cp_split(key_check(INI,FILENAME)) | stop("no format data") # ↑ #↑ 入力ファイルの名前の先頭で、 # ↑該当指定無し # | # INIファイルのどの指定を使うか判断する。 # |data変換指定を listへ変換 # 例 # 0000000001111111111222222222233333333 # 1234567890123456789012345678901234567 #sam= d d m dm da md ma ad am ddd <- こういうデータを、 #[["d",3,6],["d",6,9],["m",9,12],["d",12,13],...["d",36,37]] へ変換する。 return end #################### # 1行毎の処理 (filt_patの1行読込み毎に呼ばれる) #################### procedure format2(line) s := "" # 戻り値 line ? { # lineを走査対象として every L := !form do { # formから処理指定を順に取り出して case L[1] of { # 処理種別にて "d" : { s ||:= tab(L[2]) ; move(1) } # 1文字削除 "m" : { s ||:= (tab(L[2]) || " " || move(1)) } # その前に " "追加 "a" : { s ||:= (tab(L[2]) || move(1) || " ") } # その後に " "追加 default : stop(".INI error") } } return s ||:= tab(0) # 残りを足しこむ } end -----$ FORMAT.ICN ( lines:65 words:261 ) -------------------<cut here 長くなりますので、残りは、次回に。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: シルエット・ロマンス/ゼロ (icon407.txt 1997/12/16 PCVAN PIG) ■ Icon > Icon土日夜(8) AWK風 program(3) 風つかい 目次 今回も AWK風 programの続きです。定義 fileの読み込み対応の filter雛形 procedureです。 -----^ FILT_PA5.ICN ( date:97-12-16 time:00:28 ) -----------<cut here #################### # filter programの雛形 #################### # 1行データ処理 procedureから呼んで AWK風 filter programを作成する # # filt_patに、AWKにならって、FNR,ARGS,FILENAME,BEGIN,END を追加し、 # 定義 file読み込み処理を追加 # filt_pa5.icn Rev.01 1997/12/15 windy 風つかい H.S. # arg : ARGS : command line引数を引き継ぐ # ARGS[1]は input.file名 と想定 # wild cardsは未対応 # filt_proc : filter programの1行文処理 procedure # Usage_main: "Usage: 実行file名 " に引き続く message # out_ext : output.fileの拡張子名(指定しなければ標準出力) # in_ext : input.fileの拡張子名 # neg : input.fileの拡張子名チェックを反転 # This file is in the public domain. global FNR, ARGS, FILENAME, BEGIN, END, INI link string_e, # pre_char #入門講座4 Icon迷い道(5)参照 file_e # f_name #入門講座4 Icon回り道(4)の exe_nameと同じ # get_inil, check_ext # 入門講座4 Icon迷い道(6)参照 procedure filt_pat(ARGS,filt_proc,Usage_main,out_ext,in_ext,neg) /Usage_main := "input.file" Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成 if *ARGS > 0 then { if ARGS[1] == ("/?" | "-?") then stop(Usage) # Usage出力 else { FILENAME := map(ARGS[1]) # 第1引数を input.file名とみなす if \in_ext then { # 入力拡張子指定があれば、 # input.fileの拡張子チェック check_ext(in_ext,FILENAME,neg) | stop("input.file name error : ",FILENAME) } # input.file open in_dir := open(FILENAME) | stop("cannot open input.file : ",FILENAME) if \out_ext then { # 出力拡張子指定があれば、 out_ext := map(out_ext) line_no := 0 # 行No 動作状態 monitor用 # output.file open # output.file名作成 f_new := (pre_char(FILENAME) || "." || out_ext) out_dir := open(f_new,"a") | { # append modeで open close(in_dir) stop("cannot open output.file : ",f_new) } write(&errout,FILENAME," -> ",f_new) # 動作モニター } } } # config file読み込み INI := get_inil("INI") # list # テキスト変換指定 ################## # BEGIN 節 ################## if \BEGIN then BEGIN() # BEGINが存在すれば、BEGIN()を実行 ################## # MAIN ################## # 1行づつ input.fileから読み込んで、指定 procedureで処理をして # output.fileに書き出す。 FNR := 0 while line := read(in_dir) do { # ある行で、filt_procが失敗しても残り FNR +:= 1 # の行の処理が行われるように、いったん if (\out_ext & (*ARGS >0)) # 行を lineにセット。 then writes(&errout," ",right(FNR +:= 1,4)) # monitor表示 write(out_dir,filt_proc(line)) # filt_procが失敗してもこの行だけ失敗 } if (\out_ext & (*ARGS >0)) then { close(in_dir) # input.file close close(out_dir) # output.file close write(&errout) # monitor表示 カーサー戻し } ################## # END 節 ################## if \END then END() # ENDが存在すれば、END()を実行 end -----$ FILT_PA5.ICN ( lines:86 words:317 ) -----------------<cut here 処理例です。こういう fileを formatに食わせますと、 -----^ SAMPLE.TXT ( date:97-12-15 time:23:53 ) -------------<cut here abcdefghijklmnopqrstuvwxyz0123456abcde ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456 -----$ SAMPLE.TXT ( lines:2 words:2 ) ----------------------<cut here こういう dataへ変換されます。 -----^ SAMPLE ( date:97-12-16 time:20:07 ) -----------------<cut here abdegh ijk mnoq rs tv wx yz0 23 456de ABDEGH IJK MNOQ RS TV WX YZ0 23 456 -----$ SAMPLE ( lines:2 words:18 ) -------------------------<cut here 処理定義を変えた例です。 -----^ DATA.TXT ( date:97-12-16 time:20:08 ) ---------------<cut here abcdefghijklmnopqrstuvwxyz0123456abcde ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456 -----$ DATA.TXT ( lines:2 words:2 ) ------------------------<cut here 結果は、こうなります。 -----^ DATA ( date:97-12-16 time:20:08 ) -------------------<cut here abcdeijkl mnop qrstuvwxyz23456 a b cde ABCDEIJKL MNOP QRSTUVWXYZ23456 -----$ DATA ( lines:2 words:9 ) ----------------------------<cut here さて、次回は、wild cards file指定対応に してみたいと 思います。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: シルエット・ロマンス/ゼロ (icon408.txt 1997/12/16 PCVAN PIG) ■ Icon > Icon土日夜(9) AWK風 program(4) 風つかい 目次 さて、いよいよ、AWK風 programの最後(の予定)の wild cards対応 です。 AWKでは、file指定に wild cards 指定ができます。 wild cards対応の procedureとしては、Icon入門講座(16)で、wild.icnを紹介しています。 また、Icon入門講座4の(6)あたりでその修正をしています。これを使えば、 まあ、wild cards対応が できる ハズ です。 もう1つやりたいことがあります。AWKの wild cards 指定を使っている時に、 ここは、AWKには、合わないのかな〜? という点がありました。 wild cards指定して、複数 fileの処理をやっていて、ある fileの処理が終わ った時点ですぐ、特定の処理をしたいと言う場合に、 個々の fileの末尾が、直接には検出できませんので、細工が必要です。 ・FILENAMEが変わったら とか ・FNRが1になったら とかで、 次の file処理に入ったので、前の file末尾を過ぎた。 と判断するか、 ・AWKの自動行読み込み を使わず、自前で getline()で読み込んで、失敗し たら fileの末尾だ。 てなことをやっていました。 これは、AWKに file毎の BEGIN, ENDという機能が盛り込んで無いので、仕方が ないのです。 この辺のところが、私が AWK以外でもっと色んなことができる言語 が無いかと 探し始めた発端です。 そして、Iconのたどり着いた訳です。 せっかく、Iconで AWK風 programの雛形 を作ろうというのですから、 入れて みたい思います。 盛り込むとなれば、file毎の BEGIN, ENDを作れば良いのですから、FBEGINとか FENDとかをサポートすれば良い訳です。 という訳で、作りました。 まず、sample programです。 text fileを読み込ん で、行毎に、file毎の行番号と file通しの行番号を、付加して出力します。 -----^ TEST409.ICN ( date:97-12-19 time:22:10 ) ------------<cut here #################### # filt_pa6 の Test program #################### # 入力ファイルの行頭に行番号を付けるだけの program # test409.icn Rev.01 1997/12/19 windy 風つかい H.S. # This file is in the public domain. link filt_pa6, # filt_pat # filter雛形 string_e # top_cut # Icon入門講座2 (5)参照 procedure main(ARGS) #↓何かをセットすれば良い。"" でも良い。 filt_pat(ARGS,add_no,,,,,"f_sort") # 引数 : AARGS,filt_proc,Usage,out_ext,in_ext,neg,f_sort end #################### # BEGIN #################### procedure BEGIN() write("始めで〜す。") end #################### # FBEGIN #################### procedure FBEGIN() # ↓ FILENAMEが存在しないとき(標準入力の場合)は fail write(\FILENAME ? top_cut('\\')," の始めだよ。") # ↑directory削除 end #################### # 各行に関する処理 (filt_patから1行読込み毎に呼ばれる) #################### # FNR は、行番号(global) procedure add_no(line) return right(NR,2) || " " || right(FNR,2) || " " || line # 行番号を付加 end #################### # FEND #################### procedure FEND() write(\FILENAME ? top_cut('\\')," の終わりだよ。") end #################### # END #################### procedure END() write("終わりで〜す。") end -----$ TEST409.ICN ( lines:52 words:116 ) ------------------<cut here sample dataです。 -----^ TEST409A.DAT ( date:97-12-18 time:23:06 ) -----------<cut here The Icon Programming Language -----$ TEST409A.DAT ( lines:4 words:4 ) --------------------<cut here -----^ TEST409B.DAT ( date:97-12-18 time:23:07 ) -----------<cut here THE ICON PROGRAMMING LANGUAGE -----$ TEST409B.DAT ( lines:4 words:4 ) --------------------<cut here test409 test409b.dat test.409a.dat と実行しますと、結果は次のように なります。 -----^ TEST409 ( date:97-12-19 time:22:52 ) ----------------<cut here 始めで〜す。 test409a.dat の始めだよ。 1 1 The 2 2 Icon 3 3 Programming 4 4 Language test409a.dat の終わりだよ。 test409b.dat の始めだよ。 5 1 THE 6 2 ICON 7 3 PROGRAMMING 8 4 LANGUAGE test409b.dat の終わりだよ。 終わりで〜す。 -----$ TEST409 ( lines:14 words:34 ) -----------------------<cut here 複数 file指定をした場合には、file名順に sortしてから処理を始めています。 雛形 procedureは、次回にやります。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Memphis Underground / Herbie Mann BGD: Jasmine Tea (icon409.txt 1997/12/19 PCVAN PIG) ■ Icon > Icon土日夜(10) AWK風 program(5) 風つかい 目次 さて、wild cards指定可能な filter programの雛形 procedureの続きです。 file指定がある場合は wild cards指定の展開を行います。 無い場合(標準 入力)と処理が大分異なるため、filt_pat を、分割しています。 -----^ FILT_PA6.ICN ( date:97-12-19 time:22:07 ) -----------<cut here #################### # filter programの雛形 #################### # 1行データ処理 procedureから呼んで AWK風 filter programを作成する # AWKにならって、FNR,ARGS,FILENAME,BEGIN,END,NR を global変数に持つ。 # 定義 file読み込み処理付き。wild cards対応。 # file毎の BEGIN,ENDサポート。(FBEGIN,FEND) # filt_pa6.icn Rev.02 1997/12/19 windy file名 sort機能追加 # filt_pa6.icn Rev.01 1997/12/18 windy 風つかい H.S. # arg : ARGS : command line引数を引き継ぐ # file名指定とみなす。 file名以外の引数が必要なら # 先頭に置いて、BEGIN節で処理し、削除しておくこと。 # filt_proc : filter programの1行文処理 procedure # Usage_main: "Usage: 実行file名 " に引き続く message # out_ext : output.fileの拡張子名(指定しなければ標準出力) # in_ext : input.fileの拡張子名 # neg : input.fileの拡張子名チェックを反転 # f_sort : wild cardsを展開した file名を sortする場合 セット # This file is in the public domain. global FNR, ARGS, FILENAME, BEGIN, END, INI, NR, FBEGIN, FEND link string_e, # pre_char #入門講座4 Icon迷い道(5)参照 file_e # f_name #入門講座4 Icon回り道(4)の exe_nameと同じ # get_inil, check_ext #入門講座4 Icon迷い道(6)参照 # wild #入門講座(16), Icon入門講座4(6)参照 procedure filt_pat(ARGS,filt_proc,Usage_main,out_ext,in_ext,neg,f_sort) /Usage_main := "input.file" Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成 # .INI file読み込み INI := get_inil("INI") # list # Usage 処理 if ARGS[1] == ("/?" | "-?") then stop(Usage) # Usage出力 NR := 0 # 累積行数 ################## # BEGIN 節 programの最初に1回実行 ################## if \BEGIN then BEGIN() # BEGINが存在すれば、BEGIN()を実行 if *ARGS > 0 then { # 引数あり (= file 指定あり) # file指定解析 L := wild(ARGS) | stop(Usage) # wild cards指示 -> file名 list L := if \f_sort then sortf(L,1) # file名 sort指示があれば every LL := !L do { # 全ての fileについて FILENAME := map(LL[1]) # input.file名 filt_pat2(FILENAME,filt_proc,out_ext,in_ext,neg) } # end of every } # end of then # file指定無し else { # 標準入力 filt_pat3(FILENAME,filt_proc,out_ext,in_ext,neg) } # end of else ################## # END 節 programの最後に1回実行 ################## if \END then END() # ENDが存在すれば、END()を実行 return end #################### # file指定がある場合の file毎の処理 #################### procedure filt_pat2(FILENAME,filt_proc,out_ext,in_ext,neg) if \in_ext then { # 入力拡張子指定があれば、 # input.fileの拡張子チェック check_ext(in_ext,FILENAME,neg) | stop("input.file name error : ",FILENAME) } # input.file open in_dir := open(FILENAME) | stop("cannot open input.file : ",FILENAME) if \out_ext then { # 出力拡張子指定があれば、 out_ext := map(out_ext) line_no := 0 # 行No 動作状態 monitor用 # output.file open # output.file名作成 f_new := (pre_char(FILENAME) || "." || out_ext) out_dir := open(f_new,"a") | { # append modeで open close(in_dir) stop("cannot open output.file : ",f_new) } write(&errout,FILENAME," -> ",f_new) # 動作モニター } filt_pat3(FILENAME,filt_proc,out_ext,in_dir,out_dir) if \out_ext then { close(in_dir) # input.file close close(out_dir) # output.file close write(&errout) # monitor表示 カーサー戻し } return end #################### # file毎の処理 #################### procedure filt_pat3(FILENAME,filt_proc,out_ext,in_dir,out_dir) FNR := 0 # file毎の 行数 ################## # FBEGIN 節 fileの最初に1回実行 ################## if \FBEGIN then FBEGIN() # FBEGINが存在すれば、FBEGIN()を実行 ################## # MAIN ################## # 1行づつ input.fileから読み込んで、指定 procedureで処理をして # output.fileに書き出す。 while line := read(in_dir) do { FNR +:= 1 ; NR +:= 1 if (\out_ext & (*ARGS >0)) # 行を lineにセット。 then writes(&errout," ",right(FNR +:= 1,4)) # monitor表示 write(out_dir,filt_proc(line)) } ################## # FEND 節 fileの最後に来る度に実行 ################## if \FEND then FEND() # FENDが存在すれば、FEND()を実行 return end -----$ FILT_PA6.ICN ( lines:130 words:443 ) ----------------<cut here と、いうところで、AWK風 programの説明は、おしまいにします。後、1回 位、応用 programを説明するかも知れません。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Memphis Underground / Herbie Mann BGD: Jasmine Tea (icon410.txt 1997/12/19 PCVAN PIG) ■ Icon > Icon土日夜(11) AWK風 program(6) 風つかい 目次 あったかい日が続いていましたが、急に寒くなりました。ブルブル。こういう日 には、おうちで Iconしましょう。 AWK風 programの続きです。今回も、表形式 dataの加工です。 表形式 dataの 一部の項目を、別の変換表を使って 置換したいことが、時々あります。 そんな 時に使うものです。 まず、いつものように、定義 fileから紹介しましょう。 -----^ CONV_TB.INI ( date:97-12-23 time:18:17 ) ------------<cut here #################### # 変換処理定義 #################### # 先頭に "#"があれば comment行 # 変換 指定(同一文字が続く部分を変換 blockとみなす。) # a,b,c...は、異なった文字なら何でも差し支え無い。 $0=aaaa bbbbbb ccc # 変換 data file名 データ種別(s:文字列,n:数字列)・桁数 # 文字列と数字列は、左つめされるか右つめされるかの違い。 # $0,$1,$2,..は、異なった文字(列)なら何でも差し支え無い。 # $1,$2,$3,..は、順に変換 blockに対応していく。 $1=conv_tb1.dat s10 $2=conv_tb2.dat s8 $3=conv_tb3.dat s4 #aaaa bbbbbb ccc <- こういう指定をすると #ABCDef123456ghijYOK <- 使用前 #あいうえおef株式会社ghij横浜 <- 使用後 # conv_tb1.dat # #key data # ABCD あいうえお # EFGH かきくけこ # conv_tb2.dat # #key data # 123456 株式会社 # 123457 有限会社 # conv_tb3.dat # #key data # YOK 横浜 # TYO 東京 -----$ CONV_TB.INI ( lines:35 words:79 ) -------------------<cut here $0の部分で、変換する部分を指定します。 この例では、3箇所を変換します。 $1,$2,$3 の部分で、変換 table file名と、その属性(文字列か数字列かと桁数) を指定しています。 さて、2つ程、procedureを作ります。 ・cs_split : 変換指定文字列を、扱いやすく listにするもの。 ・read_stb : 変換 table fileを読み込んで、tableに格納するもの。 では、cs_splitから、早速 programです。 procedureと その test programが 含まれています。 なんとか splitという名前の procedureを 幾つか作っていま すが、同じ様で少しづつ違った処理です。 また、文字列出力が見易くなるように、目盛りを出力する procedureも作って みました。 -----^ CS_SPLIT.ICN ( date:97-12-23 time:22:29 ) -----------<cut here #################### # cs_split の test program #################### # cs_split.icn Rev.01 1997/12/23 windy 風つかい H.S. # This file is in the public domain. link struct_e # show_wl Icon入門講座(10)参照 procedure main() s := "aaaa bbbbbb ccc" # 置換指定の sample scale(*s +1) # 目盛り write(s) # sample文字列 show_wl(cs_split(s)) # cs_splitした結果の2重 list表示 s := " aaaa bbb bbb ccc " # 参考 scale(*s +1) write(s) show_wl(cs_split(s)) s := " " # 指定文字無し だと、どうなるかな。 scale(*s +1) write(s) s := "" # 空文字列 だと、どうなるかな。 scale(*s +1) write(s) end #################### # 文字列処理指定の文字列を解析 #################### # 処理指定 英文字1文字 # args : s : string 指定文字列 # c : cset 指定しない部分に対応する文字 # value: 2重 list(処理指定を順に詰めたもの) # [1]:指定文字, [2]:開始位置, [3]:次の指定文字の開始位置 # 指定例 00000000011111111112 # 12345678901234567890 # s1 := "ABCDef123456ghijYOK" # s2 := "aaaa bbbbbb ccc" # s2を [["a",1,5],["d",7,13],["c",17,20]] と変換する。 # 備考 : 表データの一部を置換するプログラムのために作成。上の例の用に、 # データ例と並べて指定が可能なプログラムにするため procedure cs_split(s,c) /s := &subject # default /c := ' ' # default -> ' ' L := [] # 戻り値用 list s ? { while tab(ps := upto(~c)) do { # c以外のの文字まで skip cc := move(1) # その文字を記憶 tab(pe := many(cc)) # その文字以外の文字迄 skip put(L,[cc,ps,pe]) # 文字、開始位置、次の文字の開始位置 # を list に追加 } } return L end #################### # 文字列の目盛り #################### # 文字列 procedure scale(n) s1 := "00000000011111111112222222222333333333344444444445555555555" || "66666666667777777777" s2 := "12345678901234567890123456789012345678901234567890123456789" || "01234567890123456789" write(left(s1,n)) write(left(s2,n)) return end -----$ CS_SPLIT.ICN ( lines:73 words:213 ) -----------------<cut here 走らせた結果は、次のようになります。 -----^ CS_SPLIT ( date:97-12-23 time:11:01 ) ---------------<cut here 00000000011111111112 12345678901234567890 aaaa bbbbbb ccc a 1 5 b 7 13 c 17 20 00000000011111111112 12345678901234567890 aaaa bbb bbb ccc a 2 6 b 8 11 b 12 15 c 16 19 00 12 0 1 -----$ CS_SPLIT ( lines:21 words:36 ) ----------------------<cut here 続きは、次回に。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Gently / 辛島美登里 BGD: Jasmine Tea (icon411.txt 1997/12/23 PCVAN PIG) ■ Icon > Icon土日夜(12) AWK風 program(7) 風つかい 目次 さて、もう1つの procedureです。 変換 table fileを読み込んで、tableに 格納するものです。 次のような 3つの fileを読みこむものとします。 -----^ CONV_TB1.DAT ( date:97-12-23 time:15:40 ) -----------<cut here #key data ABCD あいうえお EFGH かきくけこ -----$ CONV_TB1.DAT ( lines:3 words:6 ) --------------------<cut here -----^ CONV_TB2.DAT ( date:97-12-23 time:15:38 ) -----------<cut here #key data 123456 株式会社 123457 有限会社 -----$ CONV_TB2.DAT ( lines:3 words:6 ) --------------------<cut here -----^ CONV_TB3.DAT ( date:97-12-23 time:15:32 ) -----------<cut here #key data YOK 横浜 Yokohama TYO 東京 Tokyo -----$ CONV_TB3.DAT ( lines:3 words:8 ) --------------------<cut here 表 dataの読み込み procedureと その test programです。 read_stbは、行を読み込んで、listに変換し、tableに格納します。 その際、行を読み込んだ直後と、行を listに変換した後に、別の procedureを 呼んで dataを加工できるようにしています。 方式は、filt_patで、使ったもの と同じです。 -----^ READ_STB.ICN ( date:97-12-23 time:22:39 ) -----------<cut here #################### # read_stb.icn の test program #################### # read_stb.icn 1997/12/23 windy 風つかい H.S. # This file is in the public domain. link string_e, # split # Icon入門講座(7)、Icon入門講座3(1)参照 struct_e # tree_x # Icon入門講座3(17)、Icon入門講座4(1)の # x2tを使い、every write(x2t(x))とした procedure procedure main() L := [] # tableを読み込んで、順に listに格納 put(L,read_stb("conv_tb1.dat"), read_stb("conv_tb2.dat",,,test411b), read_stb("conv_tb3.dat",,test411a), read_stb("conv_tb3.dat",,,test411c) ) tree_x(L) # 構造体 tree表示 end ##################### # 変換 table読み込み ##################### # arg : [1]: string file name to read # [2]: 読み込み時の欄区切り文字 # [3]: 読み込み時の 行毎処理 procedure(事前処理) # [4]: 読み込み時の 行毎処理 procedure(listに変換後処理) # value : table : key:column1 -> value:column2 # function : 指定の file(表形式 data)を読み込んで、tableを作成 # 欄の先頭を keyとして、次を valueにして tableへ格納 # read_proc1が指定されていなければ、行頭が "#"なら、comment行 # として読み飛ばす。 procedure read_stb(f_name,c,read_proc1,read_proc2) dir := open(f_name) | stop("cannot open ",fname) # file読み込み T := table() # table生成 /c := ' \t' # default while s := read(dir) do { # file読み込み if /read_proc1 then { # 行毎処理指定が無ければ、 s ? if match("#") then next # comment行読み飛ばし } if \read_proc1 then s := read_proc1(s) | next # 行毎処理指定があれば # それを実行。 s ? { L := split(s,c) # 行を cで、listに分割 if \read_proc2 then { # 行毎処理指定があれば、 L := read_proc2(L) | next # その処理を行う。 } insert(T,L[1],L[2]) # tableへ格納 } # end of s } # end of while close(dir) return T end # read_proc1の sample procedure test411a(s) return s ? if match("#") then return &fail # comment行読み飛ばし else s || " Test" end # read_proc2の sample procedure test411b(L) L[1] -:= 123000 # 1番目の要素から 12300引く return L end # read_proc2の sample procedure test411c(L) L[2] := [L[2:0]] # listの2番目以降を、listにして 2番目に入れる。 return L end -----$ READ_STB.ICN ( lines:76 words:251 ) -----------------<cut here 動きを図にすると、次のようになります。 (1) conv_tb1.dat読込み (汎用 procedure) - main() ------------- -- read_stb ----------- | main() | | | | conv_tb1.dat読込 | | | | ------------------->------->-----> file読み込み | | table入手 <--------<--- | read_mtb() | | list Lに格納 | | | 1行読込み | | | | | 行毎処理(事前) | | | | | read_proc1を | | | | | 呼ぶ(指定無し) | | | | | listへ分解 | | | | | 行毎処理(事後) | | | | | read_proc2を | | | | | 呼ぶ(指定無し) | | | | | tableへ格納 | | | ---<------- (file末尾迄 繰返し)| | | | | ---------------------- ----------------------- (2) conv_tb2.dat読込み (汎用 procedure) - main() ------------- -- read_stb ----------- | main() | | | | conv_tb2.dat読込 | | | | ------------------->------->-----> file読み込み | | table入手 <--------<--- | read_mtb() | | list Lに格納 | | | 1行読込み | | | | | 行毎処理(事前) | ---------------------- | | read_proc1を | | | 呼ぶ(指定無し) | - test411b ----------- | | listへ分解 | | | | | 行毎処理(事後) | | test411b() <--------<-- | --<-------- read_proc2を | | data加工 | | | 呼ぶ | | ---------->-------->-- | -->-----> tableへ格納 | | | ---<------- (file末尾迄 繰返し)| | | | | ---------------------- ----------------------- (3) conv_tb3.dat読込み (汎用 procedure) - main() ------------- -- read_stb ----------- | main() | | | | conv_tb3.dat読込 | | | | ---------->-------->------->-----> file読み込み | | table入手 <--------<--- | read_mtb() | | list Lに格納 | | | 1行読込み | | | | | 行毎処理(事前) | ---------------------- - | --<-------- read_proc1を | / | | 呼ぶ | - test411a ----------- / - | --------> listへ分解 | | | / / | | 行毎処理(事後) | | test411a() <------- / | | read_proc2を | | data加工 | / | | 呼ぶ(指定無し) | | ---------->------ | | tableへ格納 | | | ---<------- (file末尾迄 繰返し)| | | | | ---------------------- ----------------------- (4) conv_tb3.dat読込み (汎用 procedure) - main() ------------- -- read_stb ----------- | main() | | | | conv_tb3.dat読込 | | | | ------------------->------->-----> file読み込み | | table入手 <--------<--- | read_mtb() | | list Lに格納 | | | 1行読込み | | | | | 行毎処理(事前) | ---------------------- | | read_proc1を | | | 呼ぶ(指定無し) | - test411c ----------- | | listへ分解 | | | | | 行毎処理(事後) | | test411c() <--------<-- | --<-------- read_proc2を | | data加工 | | | 呼ぶ | | ------------------->-- | -->-----> tableへ格納 | | | ---<------- (file末尾迄 繰返し)| | | | | ---------------------- ----------------------- 走らせた結果です。 変換 tableは、更に1つの listに格納して、その状態 を表示しています。 -----^ READ_STB ( date:97-12-23 time:15:45 ) ---------------<cut here <list 1> + <table 1> | + string "あいうえお" <- string "ABCD" | + string "かきくけこ" <- string "EFGH" + <table 2> | + string "有限会社" <- integer457 | + string "株式会社" <- integer456 + <table 3> | + string "東京" <- string "TYO" | + string "横浜" <- string "YOK" + <table 4> + <list 13> <- string "TYO" | + <list 12> | + string "東京" | + string "Tokyo" + <list 10> <- string "YOK" + <list 9> + string "横浜" + string "Yokohama" -----$ READ_STB ( lines:19 words:87 ) ----------------------<cut here 続きは、次回に。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Gently / 辛島美登里 BGD: Jasmine Tea (icon412.txt 1997/12/23 PCVAN PIG) ■ Icon > Icon土日夜(13) AWK風 program(8) 風つかい 目次 さて、表形式 dataの一部の項目を、別の変換表を使って 置換する programの まとめです。 filter program作成の 雛形 procedureの filt_patを使って、まとめます。 icon411は、cs_splitと read_stbが含まれる fileです。 -----^ CONV_TB.ICN ( date:97-12-23 time:22:57 ) ------------<cut here #################### # 表形式 dataの一部を、別の表 data により置換する program #################### # conv_tb.icn Rev.01 1997/12/23 windy 風つかい H.S. # This file is in the public domain. global PAT, # 変換指示 list CONV_TB, # 変換 tableが、順に入ってる list ATR, # 変換 tableの、valueの属性・桁指定 list ERROR_DIR # 変換 errorの行への tag jump用 fileの file handle link file_e, # get_inil # Icon入門講座4(13) struct_e, # tree_x # Icon入門講座3(17)、Icon入門講座4(1)の # every write(x2t(x)) だけの procedure filt_pa6, # filt_pat # filter 雛形 procedure icon411 # cs_split # 変換指定解析 # read_stb # table file読み込み #################### # filt_patを呼ぶための procedure #################### procedure main(ARGS) #↓何かをセットすれば良い。"" でも良い。 filt_pat(ARGS,conv_tb,,,,,"f_sort") # 引数 : ARGS,filt_proc,Usage,out_ext,in_ext,neg,f_sort end #################### # 1行毎の処理 (filt_patの1行読込み毎に呼ばれる) #################### # PAT, CONV_TB, ATRを全て、1つの listに入れると programは、スッキリする # が、非常にわかりにくくなるのでやめ。 procedure conv_tb(line) s := "" # 戻り値 line ? { # lineを走査対象として every i := 1 to *PAT do { # ATRから 処理指定を 順に取り出して s ||:= tab(PAT[i][2]) # 変換部より前を sに 足しこみ ss := tab(PAT[i][3]) # 変換対象文字列 if member(CONV_TB[i],ss) then { # tableの keyにあれば case ATR[i][1] of { # 属性(文字列か、数字か) "s" : s ||:= left(CONV_TB[i][ss],ATR[i][2:0]) "n" : s ||:= right(CONV_TB[i][ss],ATR[i][2:0]) default : stop(".INI error") } } else { s ||:= repl("?",ATR[i][2:0]) # 指定桁数分の "?" # error fileに書込み write(ERROR_DIR,FILENAME," ",FNR,": ",ss," ",line) } } return s ||:= tab(0) # 残りを足しこむ } end procedure BEGIN() PAT := [] ; CONV_TB := [] ; ATR := [] # list生成 #INI := get_inil("INI") # 定義 file読み込み -> filt_patある get(INI) # "$0"読み飛ばし PAT := cs_split(get(INI)) # 処理指定を、cs_splitで処理して、PATへ代入 while get(INI) do { # "$1",...読み飛ばし。その後のみ使用 get(INI) ? L := split() # 変換 file指定と 属性指定を listへ put(CONV_TB,read_stb(L[1])) # 変換 table fileを読み込み tableへ格納し # 更にその tableを list CONV_TBへ格納 put(ATR,L[2]) # 変換 tableの属性を list ATRへ格納 } # error log file を open ERROR_DIR := open(s := "error.log","w") | stop("cannot open ",s) # clear ERROR_DIR := open(s := "error.log","a") | stop("cannot open ",s) write("PAT") ; tree_x(PAT) write("CONV_TB") ; tree_x(CONV_TB) write("ATR") ; tree_x(ATR) write() return end procedure END() close(ERROR_DIR) # error log file を close return end -----$ CONV_TB.ICN ( lines:81 words:312 ) ------------------<cut here こういう data fileを変換します。 -----^ TEST411.DAT ( date:97-12-23 time:18:02 ) ------------<cut here ABCDef123456ghijYOK EFGHef123457ghijTYO ABCDef123458ghijXYZ -----$ TEST411.DAT ( lines:3 words:3 ) ---------------------<cut here 結果です。 結果出力の前に、変換情報が入っている list(PAT,CONV_TB,ATR) の内容を書出しています。 -----^ CONV_TB ( date:97-12-23 time:18:27 ) ----------------<cut here PAT <list 6> + <list 7> | + string "a" | + integer1 | + integer5 + <list 8> | + string "b" | + integer7 | + integer13 + <list 9> + string "c" + integer17 + integer20 CONV_TB <list 4> + <table 1> | + string "あいうえお" <- string "ABCD" | + string "かきくけこ" <- string "EFGH" + <table 2> | + string "有限会社" <- string "123457" | + string "株式会社" <- string "123456" + <table 3> + string "東京" <- string "TYO" + string "横浜" <- string "YOK" ATR <list 5> + string "s10" + string "s8" + string "s4" あいうえおef株式会社ghij横浜 かきくけこef有限会社ghij東京 あいうえおef????????ghij???? -----$ CONV_TB ( lines:34 words:106 ) ----------------------<cut here 変換できなかった部分は、error logに書出します。 -----^ ERROR.LOG ( date:97-12-23 time:22:58 ) --------------<cut here d:\icon\lec45\test411.dat 3: 123458 ABCDef123458ghijXYZ d:\icon\lec45\test411.dat 3: XYZ ABCDef123458ghijXYZ -----$ ERROR.LOG ( lines:2 words:8 ) -----------------------<cut here これで、AWK風 programのお話は(多分)おしまいです。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Get Back / Ike & Tina Turner BGD: Jasmine Tea (icon413.txt 1997/12/23 PCVAN PIG) ■ Icon > Icon土日夜(14) AWK風 program(9) 風つかい 目次 ううっ。(11)の書込みを見直していましたら、ミスがみつかりました。 many(c)の仕様を勘違いしていました。 many(c)は、現在の走査位置(&pos)から走査して、c以外の文字の出現位置を 見つける関数ですが、現在走査位置がいきなり c以外だったら failするという 仕様になっています。 s := " aaaa bbbbbbc d ef" の c,d,e,fのように、1文字の指定の場合に うまく動きませんでした。 ということで修正です。 -----^ CS_SPLIT.ICN ( date:97-12-27 time:10:27 ) -----------<cut here #################### # cs_split の test program #################### # cs_split.icn Rev.02 1997/12/27 windy cs_split修正 # cs_split.icn Rev.01 1997/12/23 windy 風つかい H.S. # This file is in the public domain. link struct_e # show_wl Icon入門講座(10)参照 procedure main() s := "aaaa bbbbbb ccc" # 置換指定の sample scale(*s +1) # 目盛り write(s) # sample文字列 show_wl(cs_split(s)) # cs_splitした結果の2重 list表示 s := " aaaa bbb bbb ccc " # 参考 scale(*s +1) write(s) show_wl(cs_split(s)) s := " aaaa bbbbbbc d ef" # (Rev.02)(Rev.01ではうまく動かない。) scale(*s +1) write(s) show_wl(cs_split(s)) s := " " # 指定文字無し だと、どうなるかな。 scale(*s +1) write(s) s := "" # 空文字列 だと、どうなるかな。 scale(*s +1) write(s) end #################### # 文字列処理指定の文字列を解析 #################### # 処理指定 英文字1文字 # args : s : string 指定文字列 # c : cset 指定しない部分に対応する文字 # value: 2重 list(処理指定を順に詰めたもの) # [1]:指定文字, [2]:開始位置, [3]:次の指定文字の開始位置 # 指定例 00000000011111111112 # 12345678901234567890 # s1 := "ABCDef123456ghijYOK" # s2 := "aaaa bbbbbb ccc" # s2を [["a",1,5],["d",7,13],["c",17,20]] と変換する。 # 備考 : 表データの一部を置換するプログラムのために作成。上の例の用に、 # データ例と並べて指定が可能なプログラムにするため procedure cs_split(s,c) /s := &subject # default /c := ' ' # default -> ' ' L := [] # 戻り値用 list s ? { while tab(ps := upto(~c)) do { # c以外の文字まで skip cc := move(1) # その文字を記憶 tab(pe := (many(cc) | &pos)) # その文字以外の文字迄 skip(Rev.02) # ↑many(c)は、現在の走査位置(&pos)の文字が、c以外だったら # failするので。 | &posを付加。 これが無いと、変換指定が # 1文字の時にうまく動かない。 put(L,[cc,ps,pe]) # 文字、開始位置、次の文字の開始位置 # を list に追加 } } return L end #################### # 文字列の目盛り #################### # 文字列 procedure scale(n) s1 := "00000000011111111112222222222333333333344444444445555555555" || "66666666667777777777" s2 := "12345678901234567890123456789012345678901234567890123456789" || "01234567890123456789" write(left(s1,n)) write(left(s2,n)) return end -----$ CS_SPLIT.ICN ( lines:82 words:243 ) -----------------<cut here many(c)が失敗した場合の手当をするやり方の他に、失敗しないように1文字分 戻してあげるというやり方もあります。 ----- cc := move(1) # その文字を記憶 move(-1) # many(c)対策 # ↑many(c)は、現在の走査位置(&pos)の文字が、c以外だったら # failするので、戻す。 tab(pe := many(cc)) # その文字以外の文字迄 skip ----- また、現在走査位置の文字を取り出すのに move(1)を使わず、&posで文字列 から取り出すやり方もあります。 これが、一番素直かな。 ----- cc := s[&pos] # その文字を記憶 tab(pe := many(cc)) # その文字以外の文字迄 skip ----- 動かした結果です。 -----^ CS_SPLI2 ( date:97-12-27 time:10:21 ) ---------------<cut here 00000000011111111112 12345678901234567890 aaaa bbbbbb ccc a 1 5 b 7 13 c 17 20 00000000011111111112 12345678901234567890 aaaa bbb bbb ccc a 2 6 b 8 11 b 12 15 c 16 19 00000000011111111112 12345678901234567890 aaaa bbbbbbc d ef a 2 6 b 8 14 c 14 15 d 16 17 e 18 19 f 19 20 00 12 0 1 -----$ CS_SPLI2 ( lines:31 words:60 ) ----------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Pureness / 岡本真夜 BGD: Jasmine Tea (icon414.txt 1997/12/27 PCVAN PIG) ■ Icon > Icon土日夜(15) record 風つかい 目次 年が変わって、あらら、もう下旬になってしまいました。 今年は、横浜では、 正月早々、大雪がありまして、雪かきで忙しくて。(まさか) 今日のTVで、関東で降る雪は水分が多いとか言っていました。東北の雪だと サラサラしていて、 水分は8%位ですが、 関東の雪では、その4倍位のベタ雪 が多いそうです。 津軽恋女では 7種類の雪が降る と唄っています。 こな雪、つぶ雪、わた雪、 ざらめ雪、みず雪、かた雪、氷雪。 横浜にいると、雪の表現で使うのは、精々 粉雪とベタ雪 くらいでしょうか。 何かで、エスキモーには、40種類以上の雪の表現があるとか 読みましたが、 カタギの方見ると program言語なんて、多分、数種しかないと思われているんで しょうが、 実際は、1000種類以上あるみたいですから、雪に 数10種あっても オカシクはありませんね。(比べる問題じゃないような気もします。あはは) さて、今年の入門講座では、今までやりたいと思って なかなか できてません ・数式展開 ・簡単な assembler の説明したいと思います。 できれば、更に 構文解析 tool(parser)あたりまで できると良いんですけれど。 この辺は、Iconの libraryには、ちゃんとそれら しき procedureとか、parser program(IBPAG: Icon-Based Parser Generator)も あるんですが、勉強が追い付いていません。 さて、今回は、今年の希望とは 裏腹 に、recordがテーマです。 Iconには、listという data構造があります。階層構造の dataを表わすのに非常 に便利ですので、多用しています。 しかし、階層が深い listを使いますと、programを書いているときは良いんです が、しばらく経った後に読んだ時に、サッパリ分からなくなっています。 例えば、入門講座3 Icon雑記帳(15)ビデオ問題/簡易解法 で、こんな所が あります。 if (L_out[i][1][1] +LL[3]) <= t_max then { # ダビング可能? L_outは、3階層の listですが、iは多分 loopを回しているんでしょうが、その 後の [1][1] とかは、書いた本人が、なんだっけ!? となります。 すぐ下の commentには、 # [i]: テープ番号 # [i][1]: 詰め込み時間 (初期値 : [0,"分"]) と あります。 i は tape No、次の [1]は詰め込み時間と 単位を入れた listで、 その次の [1]は、詰め込み時間と commentを読んで分かりますが、もっと直感的に できないものかと、実は思っていました。 例えば、L_out.tape_no.time_rec.time という風に、名前で呼べないものかな。 ↑[i] ↑[1] ↑[1] 名前で呼ぶ? ううっ。どこかで聞いたような。そうだ、recordは、そんなことが できるんだった。 そうか、recordは、こんな時に使うんだろう。と、教典(The Icon Programming Language)を、読み直してみましたら、ヤッパそうみたい。 簡単な test programで試してみます。 -----^ REC.ICN ( date:98-01-17 time:21:24 ) ----------------<cut here #################### # recordの習作 #################### # rec.icn Rev.1.1 1998/01/17 windy 風つかい H.S. # This file is in the public domain. record r1(a,b) # record構成宣言 record r2(x,y,z) # record構成宣言 procedure main() R1 := r1(10) # record R1を生成(R1.aを 10とする。) R1.b := r2(20,30,40) # R1.bに record を代入。 R1.a.xを 20, # R1.a.yを 30, R1.a.zを 40とする。 write(R1.a) # R1.aを書き出し write(R1.b.x) # R1.b.xを書き出し write(R1.b.y) # R1.b.yを書き出し write(R1.b.z) # R1.b.zを書き出し end -----$ REC.ICN ( lines:18 words:63 ) -----------------------<cut here 結果です。 -----^ REC ( date:98-01-17 time:21:24 ) --------------------<cut here 10 20 30 40 -----$ REC ( lines:4 words:4 ) -----------------------------<cut here それから、以前の説明(Icon日記(29) record)で、間違った説明をして いますね。「 recordの scope(有効範囲)は、global(全域)です。」は 間違いで、「 record構成宣言の scopeは、 global(全域)です。」のミスで す。すみません。 構成宣言が globalなのは、ある procedureが 別の procedureに、recordで dataを渡したとき、受け取った側で、再度 record構成宣言しなくても 良いた めには、当然ですね。 recordが、便利に使えそうですので、次回は 構造体 tree表示 procedureを record対応への拡張を、やってみたいと思います。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 津軽恋女 / 新沼謙治 BGD: Jasmine Tea (icon415.txt 1998/01/25 PCVAN PIG) ■ Icon > Icon土日夜(16) 構造体 tree表示(1) 風つかい 目次 気象予報士の方が、TVで、今年は暖冬なので大雪が降りやすいと言っています が、シロ〜トには良く分かりません。 さて、今回は、構造体を tree表示する procedureを record対応にします。 ついでに、これまでに見つかったミスもいくつか修正しています。 せっかくですので、 早速、program中に recordを使いました。 recordは listに似ていますので、最初は単純に listかどうか判定している部分 を listでも recordでも良いようにと変更してみたましたが、うまく動きません。 問題は typeでした。 dataの typeを判断する関数 type()を使っているのですが recordに対して、type()を使っても "record"とは返って来ないのですね。 record構成宣言で record type_id(type,multi) # record構成宣言 と、宣言しておいて、 X_record := type_id() # 要素が (&null,&null)の record と、 recordを生成しておいて、 type(X_record) としますと、"type_id"と返って 来ます。 record構成宣言する度に、新しい typeが発生します。この辺でハマりましたが なんとか record対応にできました。 typeの扱いが複雑になりますので、type判定 procedureを追加しています。 -----^ X2TREE08.ICN ( date:98-01-18 time:18:14 ) -----------<cut here #################### # 構造体の構成を tree表示 #################### # x2tree08.icn 1998/01/18 windy 風つかい H.S. # 機能追加: x2tree07を record対応に拡張 # ミス修正: 1) list,set,table,record以外を指定するとコケた。 # 2) x2t,x2treeのそこかしこ。 # This file is in the public domain. #################### # 構造体の構成を tree表示 #################### # args : [1]: なんでも良い [2]:treeの列の進み # Usage : tree_x(x,step) global T_serial record type_id(type,multi) # record構成宣言 link sjis_e # jimage procedure tree_x(x,step) every write(x2t(x,step)) end #################### # 構造体の構成を tree状に見せる generator (recursive) #################### # args : [1]: なんでも良い [2]:treeの列の進み # value : sequence of string (treeの1行分) # Usage : every write(x2t(x)) procedure x2t(x,step) # generator # topの処理 n_type := 8 # type表示の桁数 T_serial := table() # serial No 登録用 table生成 ss := repl(" ", \step | 0) TI_x := type_x(x) # typeチェック if TI_x.multi ~== "multi" # list,set,table,recordでなければ then return left(TI_x.type,n_type) || jimage(x) # 書き出す else { # list,set,table,recordなら suspend "<" || TI_x.type || " " || (m := string(serial(x))) || ">" #↑serial No # その typeに対する serial No 登録用 setが無ければ生成 if /(T_serial[TI_x.type]) then T_serial[TI_x.type] := set() insert(T_serial[TI_x.type],m) #←serial No 登録 # serial Noを T_serial[TI_x.type]に登録 suspend " " || ss || x2tree(x,ss) # 更に解析 } end #################### # x2t の sub-procedure #################### procedure x2tree(x,ss) n := *x # 枝の末端検出用カウンタ n_type := 8 # type表示の桁数 TI_x := type_x(x) if TI_x.type ~== "table" then { # list,set,table,record every xx := !x do { # 構造体の要素を1つ づつ取り出す n -:= 1 TI_xx := type_x(xx) val_disp := if TI_xx.multi == "multi" then "+ <" || TI_xx.type || " " || string(m := serial(xx)) || ">" else "+ " || left(TI_xx.type,n_type) || jimage(xx) case TI_xx.multi of { # 構造体の typeにより、 "string" : suspend val_disp #↓list,set,table,recordなら、typeを書出してその中身をまた解析する。 "multi" : { # その typeに対する serial No 登録用 setが無ければ生成 if /(T_serial[TI_xx.type]) then T_serial[TI_xx.type] := set() #↓再帰構造で なければ。 #(T_serial[TI_xx.type] に既に登録済みなら再帰構造) if not member(T_serial[TI_xx.type],m) then { insert(T_serial[TI_xx.type],m) #←serial No 登録 # serial Noを T_serial[TI_xx.type]へ登録 suspend val_disp suspend (if n > 0 then "| " else " ") || ss || ss || x2tree(xx,ss) #↑枝の途中 #↑枝の末端 # 再帰↑ delete(T_serial[TI_xx.type],m) #←serial No 登録を削除 } else { # 再帰構造 ならば、書き出すとキリが無いので打止め suspend val_disp || " (Recursion)" } } #↓その他なら、typeと値を書き出す。 default : suspend val_disp } } } else { # table every xkey := key(x) do { # tableの keyを1つ づつ取り出す n -:= 1 TI_key := type_x(xkey) key_disp := if TI_key.multi == "multi" then " <- <" || TI_key.type || " " || string(serial(xkey)) || ">" else " <- " || left(TI_key.type,n_type) || jimage(xkey) # valueの取り出し xx := x[xkey] TI_xx := type_x(xx) val_disp := if TI_xx.multi == "multi" then "+ <" || TI_xx.type || " " || string(m := serial(xx)) || ">" else "+ " || left(TI_xx.type,n_type) || jimage(xx) # 以降は list,set,table,recordとほぼ同じ。 # 書き出しの際に key_disp を付加するところだけが異なる。 case TI_xx.multi of { # 構造体の typeにより、 "string" : suspend val_disp || key_disp #↓list,set,table,recordなら、typeを書出して、その中身をまた解析する。 "multi" : { # その typeに対する serial No 登録用 setが無ければ生成 if /(T_serial[TI_xx.type]) then T_serial[TI_xx.type] := set() #↓再帰構造で なければ。 #(T_serial[TI_xx.type)]に既に登録済みなら再帰構造) if not member(T_serial[TI_xx.type],m) then { insert(T_serial[TI_xx.type],m) #←serial No 登録 # serial Noを T_serial[TI_xx.type]へ登録 suspend val_disp || key_disp suspend (if n > 0 then "| " else " ") || ss || ss || x2tree(xx,ss) #↑枝の途中 #↑枝の末端 # 再帰↑ delete(T_serial[TI_xx.type],m) #←serial No 登録を削除 } else { # 再帰構造 ならば、書き出すとキリが無いので打止め suspend val_disp || key_disp || " (Recursion)" } } #↓その他なら、typeと値を書き出す。 default : suspend val_disp || key_disp } } } end #################### # type判定 #################### procedure type_x(x) TI := type_id() # record生成 TI.type :=type(x) case TI.type of { "string" : TI.multi := "string" ("cset" | "file" | "integer" | "null" | "procedure" | "real" | "co-expression") : TI.multi := "single" ( "set" | "list" | "table") : TI.multi := "multi" default : TI.multi := "multi" # record } return TI end -----$ X2TREE08.ICN ( lines:154 words:594 ) ----------------<cut here 行数制限がありますので、この procedureの test programは次回にします。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Je l'aime - チェンバロに恋して - / 曽根麻矢子 BGD: Rolling-K (icon416.txt 1998/01/25 PCVAN PIG) ■ Icon > Icon土日夜(17) 構造体 tree表示(2) 風つかい 目次 さて、今回は、前回作った 構造体 tree表示 procedureの test programです。 従来のものの後に、recordの testの部分を追加しています。 更に、今までは いきなり構造を持たない stringや integerなどが指定されると動作がオカシク なりました。この修正の確認部分も追加しています。 -----^ X2TREE8~.ICN ( date:98-01-18 time:16:51 ) -----------<cut here #################### # test driver for x2tree08.icn #################### # x2tree8~.icn 1998/01/18 windy 風つかい H.S. # This file is in the public domain. record r1(a,b) # record構成宣言 record r2(x,y,z,w) # record構成宣言 link x2tree08 procedure main() #listの test L1 := ["A","B"] L2 := ["C","D"] L3 := ["E","F"] put(L1,L2) put(L2,L3) put(L1,L3) # 別枝 test put(L3,L1) # listの再帰 every write(x2t(L1) \20) # \20は、テストをドジッた時に、20個で止めるため。 write() #tableの test T := table() T["A"] := "G" T["C"] := L2[1] T["E"] := L3 T[L1] := L1[1] put(L3,T) # tableの再帰 every write(x2t(T) \20) write() #setの test L4 := ["H","I"] S1 := set(["L","M"]) S := set(["J","K",L4]) insert(S,S1) insert(S1,S) # setの再帰 every write(x2t(S) \20) write() # recordの test R1 := r1(10) # record R1を生成。R1.aを 10とする。 R2 := r2("2X","2Y") # R2を生成。R2.xを "2X"、 R2.y を "2Y"とする。 R3 := r1("1A","1B") # R3を生成。R3.aを "1A"、 R3.b を "1B"とする。 R1.b := R2 # R2を R1.bに代入。 R2.z := R1 # 再帰 R2.w := R3 every write(x2t(R1) \20) write() every write(x2t(R1.a) \20) every write(x2t("ABCD") \20) end -----$ X2TREE8~.ICN ( lines:54 words:155 ) -----------------<cut here 結果です。 recordの type名のところには、 record構成宣言した、"r1"とか "r2"とかが出てきます。 -----^ X2TREE8~ ( date:98-01-18 time:18:10 ) ---------------<cut here <list 1> + string "A" + string "B" + <list 2> | + string "C" | + string "D" | + <list 3> | + string "E" | + string "F" | + <list 1> | + string "A" | + string "B" | + <list 2> (Recursion) | + <list 3> (Recursion) + <list 3> + string "E" + string "F" + <list 1> + string "A" + string "B" <table 2> + string "C" <- string "C" + <list 3> <- string "E" | + string "E" | + string "F" | + <list 1> | | + string "A" | | + string "B" | | + <list 2> | | | + string "C" | | | + string "D" | | | + <list 3> (Recursion) | | + <list 3> (Recursion) | + <table 2> | + string "C" <- string "C" | + <list 3> <- string "E" (Recursion) | + string "A" <- <list 1> | + string "G" <- string "A" + string "A" <- <list 1> + string "G" <- string "A" <set 5> + string "K" + <set 4> | + <set 5> | | + string "K" | | + <set 4> (Recursion) | | + string "J" | | + <list 64> | | + string "H" | | + string "I" | + string "M" | + string "L" + string "J" + <list 64> + string "H" + string "I" <r1 1> + integer 10 + <r2 1> + string "2X" + string "2Y" + <r1 1> | + integer 10 | + <r2 1> (Recursion) + <r1 2> + string "1A" + string "1B" integer 10 string "ABCD" -----$ X2TREE8~ ( lines:73 words:284 ) ---------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Je l'aime - チェンバロに恋して - / 曽根麻矢子 (icon417.txt 1998/01/25 PCVAN PIG) ■ Icon > Icon土日夜(18) n進数計算 風つかい 目次 時々、n進数の計算が必要になることがあります。 月は、1月〜12月 ですし 時は24時間とか、分、秒は、60が単位ですし、いろんなところで出てきます。 国際単位(SI単位)には、秒しか無いのですが、時刻の表現に通常使う年、月、 日、時、分までは、SI単位にしろという話は無いみたいですね。 時刻で時々、うるう秒というのがありますね。この時は、0秒から60秒迄存在し ます。 しかし大抵の softwareは、うるう秒迄は 配慮していませんので、私の知っている 範囲では、computerの時計を合わせ直すか、computer用マスター時計で、うるう秒の 前の 10秒を各々 1.1秒 ずつにして60秒目が発生しないようにするとかしています。 厳密な時刻が必要な場合は、どうやっているんでしょうか。60秒目が存在しても 良いような programになっているんでしょうね。 さて、そういう10進数以外の 数字を扱うための procedureを作ってみました。 defaultでは、月計算を行うようにしています。 -----^ ADD_NO.ICN ( date:98-02-11 time:21:44 ) -------------<cut here #################### # n進数の整数の足し算 #################### # add_no.icn Rev.1.2 1998/02/11 windy comment修正 # add_no.icn Rev.1.1 1998/02/11 windy 風つかい H.S # This file is in the public domain. #################### # increment No (limit付き) #################### # arg: [1]: n: integer 対象数 # [2]: mini: integer 最小値 # [3]: max: integer 最大値 # value [result,carry] procedure inc_no(n,mini,max) /mini := 1 /max := 12 return if n = max then [mini,+1] else [n+1, 0] end #################### # decrement No (limit付き) #################### # arg: [1]: n: integer 対象数 # [2]: mini: integer 最小値 # [3]: max: integer 最大値 # value [result,carry] procedure dec_no(n,mini,max) /mini := 1 /max := 12 return if n = mini then [max,-1] else [n-1, 0] end #################### # add No (limit付き) #################### # arg: [1]: n: integer # [2]: m: integer # [3]: mini: integer # [4]: max: integer # value [result,carry] procedure add_no(n,m,mini,max) /mini := 1 /max := 12 /m := 0 radix := max-mini+1 # 基数 org_0 := n-mini +m # 0 開始数での計算 if org_0 >= 0 then { # 正の数(か 0) carry := org_0 / radix # 桁上がり result := org_0 % radix +mini } else { # 負の数 carry := (org_0 +1) / radix -1 # 桁下がり result := (org_0 -carry*radix ) % radix +mini } return [result,carry] end -----$ ADD_NO.ICN ( lines:64 words:210 ) -------------------<cut here test programです。 -----^ ADD_NO~.ICN ( date:98-02-11 time:21:45 ) ------------<cut here #################### # test program for add_no.icn #################### # add_no~.icn Rev.1.2 1998/02/11 windy comment修正 # add_no~.icn Rev.1.1 1998/02/11 windy 風つかい H.S. # This file is in the public domain. link add_no procedure main() write("10進 0-9 -> +1 : 普通の桁上がり") every writes(" ",(L := inc_no(0 to 9,0,9))[1],":",L[2]) write("\n10進 1-10 -> +1") every writes(" ",(L := inc_no(1 to 10,1,10))[1],":",L[2]) write("\n12進 1-12 -> +1: 月の計算") every writes(" ",(L := inc_no(1 to 12))[1],":",L[2]) write("\n\n10進 0-9 -> -1 : 普通の桁下がり") every writes(" ",(L := dec_no(0 to 9,0,9))[1],":",L[2]) write("\n10進 1-10 -> -1") every writes(" ",(L := dec_no(1 to 10,1,10))[1],":",L[2]) write("\n12進 1-12 -> -1: 月の計算") every writes(" ",(L := dec_no(1 to 12))[1],":",L[2]) write("\n\n12進 7 -> +0〜13 : 月の計算") every writes(" ",(L := add_no(7,0 to 13))[1],":",L[2]) write("\n12進 7 -> +14〜27 : 月の計算") every writes(" ",(L := add_no(7,14 to 27))[1],":",L[2]) write("\n12進 7 -> -0〜-13 : 月の計算") every writes(" ",(L := add_no(7,0 to -13 by -1))[1],":",L[2]) write("\n12進 7 -> -14〜27 : 月の計算") every writes(" ",(L := add_no(7,-14 to -27 by -1))[1],":",L[2]) write() end -----$ ADD_NO~.ICN ( lines:31 words:162 ) ------------------<cut here 結果です。 -----^ ADD_NO~ ( date:98-02-11 time:21:45 ) ----------------<cut here 10進 0-9 -> +1 : 普通の桁上がり 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 0:1 10進 1-10 -> +1 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0 1:1 12進 1-12 -> +1: 月の計算 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0 11:0 12:0 1:1 10進 0-9 -> -1 : 普通の桁下がり 9:-1 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 10進 1-10 -> -1 10:-1 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 12進 1-12 -> -1: 月の計算 12:-1 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0 11:0 12進 7 -> +0〜13 : 月の計算 7:0 8:0 9:0 10:0 11:0 12:0 1:1 2:1 3:1 4:1 5:1 6:1 7:1 8:1 12進 7 -> +14〜27 : 月の計算 9:1 10:1 11:1 12:1 1:2 2:2 3:2 4:2 5:2 6:2 7:2 8:2 9:2 10:2 12進 7 -> -0〜-13 : 月の計算 7:0 6:0 5:0 4:0 3:0 2:0 1:0 12:-1 11:-1 10:-1 9:-1 8:-1 7:-1 6:-1 12進 7 -> -14〜27 : 月の計算 5:-1 4:-1 3:-1 2:-1 1:-1 12:-2 11:-2 10:-2 9:-2 8:-2 7:-2 6:-2 5:-2 4:-2 -----$ ADD_NO~ ( lines:22 words:174 ) ----------------------<cut here 以前作った、年月の+1月、−1月 procedureを inc_noと dec_noを使って 書き換えてみました。 -----^ MONTH2.ICN ( date:98-02-11 time:21:46 ) -------------<cut here #################### # 年月データ(YYMM)の+−1月計算 #################### # month2.icn Rev.1.1 1998/02/11 windy comment修正. # month2.icn Rev.1.1 1998/02/11 windy 風つかい H.S. # This file is in the public domain. link add_no procedure main() every writes(" ",inc_month("9901" | "9902" | "9911" | "9912" | "0001" | "0002")) write() write("↑+1月") every writes(" ", "9901" | "9902" | "9911" | "9912" | "0001" | "0002") write() write("↓−1月") every writes(" ",dec_month("9901" | "9902" | "9911" | "9912" | "0001" | "0002")) write() end procedure dec_month(YYMM) # 年月データ −1月 yy := (numeric(YYMM[1:3])+100) ; mm := numeric(YYMM[3:0]) # 年月を数字に変換 L := dec_no(mm) # 年データを文字列へ変換し、2桁で右寄せであまりに"0"を詰める。月も同じ。 # ↓文字列の連結 return right(string(yy +:= L[2]),2,"0") || right(string(L[1]),2,"0") end procedure inc_month(YYMM) # 年月データ +1月 yy := (numeric(YYMM[1:3])) ; mm := numeric(YYMM[3:0]) # 年月を数字に変換 L := inc_no(mm) return right(string(yy +:= L[2]),2,"0") || right(string(L[1]),2,"0") end -----$ MONTH2.ICN ( lines:38 words:125 ) -------------------<cut here 念のため結果を。 -----^ MONTH2 ( date:98-02-11 time:21:46 ) -----------------<cut here 9902 9903 9912 0001 0002 0003 ↑+1月 9901 9902 9911 9912 0001 0002 ↓−1月 9812 9901 9910 9911 9912 0001 -----$ MONTH2 ( lines:5 words:20 ) -------------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Je l'aime - チェンバロに恋して - / 曽根麻矢子 (icon418.txt 1998/02/11 PCVAN PIG) ■ Icon > Icon土日夜(19) table書き出し 風つかい 目次 梅は咲いたか、桜はまだかいな? の季節になりました。 今年は暖冬ですの で、梅はもう先月から咲いていますが、桜は未だ未だですね。 program言語は、言語の一種と思います。すると、programを書くのは文章を書 くのと同じということになります。 文章をうまく書くのは、理科系の方より文化系の方のほうが、普通うまい とい う気がします。 ということで、多分理科系の方が多い programerの書く programは大抵 分かり 難いということになりますね。 さて、tableは、AWKや Perlや pythonにも有りますが、とても便利なものです。 AWKを勉強していた時、tableがうまく使えると programがスッキリして 分かり やすくなり、おまけに 速い programになって、これは スゴイ と感動した覚えが あります。 私の場合、tableを書き出す機会は、余り無いのですが、たまにやって悩みまし たので、汎用の書き出し用の procedureを作ってみました。 細かい加工は、その時その時で変わりますので、別の 加工用 procedureを呼べ るようにしてあります。 -----^ SHOW_TBL.ICN ( date:98-02-11 time:23:18 ) -----------<cut here #################### # table の key/value(list/record でも良い) 表示用 procedure #################### # keyで sortして、keyと value(valueが list/record ならその要素)を 生成 #################### # show_tbl.icn Rev1.2 98/02/11 windy comment修正 # show_tbl.icn Rev1.1 98/02/07 windy show_tbを generatorにする。 # show_tb.icn Rev1.2 98/02/06 windy show,show2,show_tb,sortshowを統合 # show_tb.icn Rev1.1 95/11/12 windy 風つかい H.S. # arg: [1]: T: table # [2]: c: character: 出力区切り文字 # [3]: proc1: procedure: keyを加工して出力する際の procedure # [4]: proc2: procedure: valueを加工して出力する際の procedure # value: string # output: key c value[1] c value[2] c ... valueが list,record # key c value c value c ... valueが string,number # Usage: every s := show_tbl(T,c,proc1,proc2) do write(s) # every write(show_tbl(T,c,proc1,proc2)) # 注 tableの key,valueは、最終的には印字可能であること。 # This file is in the public domain. procedure show_tbl(T,c,proc1,proc2) /c := "\t" # default(出力区切り文字) tab L := sort(T,3) # keyで sort -> key,value交互の list # ↓keyを取り出し proc1が定義してあれば その処理 while s := if /proc1 then get(L) else proc1(get(L)) do { # valueを取り出して、proc2が定義してあれば その処理をして x := if /proc2 then get(L) else proc2(get(L)) if type_r(x) == ("list" | "record") # typeを check # list か recordなら その要素を then every s ||:= (c || !x) else s ||:= (c || x) # ↑それ以外ならそのまま suspend s } end #################### # recordなら "record"と返す type #################### # arg: 任意 # value: string procedure type_r(x) return if match("record",image(x)) then "record" else type(x) end -----$ SHOW_TBL.ICN ( lines:49 words:210 ) -----------------<cut here show_tbを使って、table内容を書き出す test programです。 -----^ SHOW_TB2.ICN ( date:98-02-11 time:23:20 ) -----------<cut here #################### # show_tbl の test program #################### # Rev.1.2 show_tb2.icn 1998/02/11 windy comment修正 # Rev.1.1 show_tb2.icn 1998/02/07 windy 風つかい H.S. # This file is in the public domain. link show_tbl, # show_tbl hexcvt # hexstring(BIPL) 10進数 -> 16進数変換 procedure main() T1 := table() # table生成 # key↓value↓key↓value↓key↓value↓ L1 := ["γ","春子","β","夏子","α","秋子"] while insert (T1,get(L1),get(L1)) # tableへ格納 every write(show_tbl(T1," ")) # table内容書き出し write() T2 := table() # table生成 # key1↓ value1↓ key2↓ value2↓ key3↓ value3↓ L2 := ["C",["A1","B1","C1"],"B",["A2","B2","C2"],"A",["A3","B3","C3"]] while insert (T2,get(L2),get(L2)) # tableへ格納 every write(show_tbl(T2," ")) # table内容書き出し write() T3 := table() # key↓value↓ key↓ value↓ key↓ value↓ L3 := ["Z",[10,16],"Y",[100,256],"X",[1000,1024]] while insert (T3,get(L3),get(L3)) # tableへ格納 every write(show_tbl(T3," ",image,test_form)) # table内容書き出し end # 書き出し時の処理 # L の 第1要素は4桁の16進数へ変換し、第2要素は4桁右詰め処理 procedure test_form(L) return [hexstring(L[1],4),right(L[2],4)] end -----$ SHOW_TB2.ICN ( lines:36 words:121 ) -----------------<cut here 結果です。 -----^ SHOW_TB2 ( date:98-02-11 time:23:21 ) ---------------<cut here α 秋子 β 夏子 γ 春子 A A3 B3 C3 B A2 B2 C2 C A1 B1 C1 "X" 03E8 1024 "Y" 0064 256 "Z" 000A 16 -----$ SHOW_TB2 ( lines:11 words:27 ) ----------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: SMILE / 岡本真夜 (icon419.txt 1998/02/11 PCVAN PIG) ■ Icon > Icon土日夜(20) table読み込み(1) 風つかい 目次 前回、table書き出しをやりましたので、今回は、table読み込みです。 別 fileから tableを読み込むのは、第12回の AWK風 program(7)でやって います。 似たような処理ですが、今回は 複数の tableがファイルに含まれて いるケースをやります。 次のような tableを含んだ fileがあるとします。 以前使った 惑星の dataと、 単純な曜日 dataです。 こういう tableを programに読み込んで、programの中で、table参照できるように しようという訳です。 -----^ READ_MTB.DAT ( date:98-02-12 time:22:18 ) -----------<cut here #################### # read_mtb test用 data file #################### # read_mtb.dat Rev.1.1 1998/02/12 windy 風つかい H.S. # 先頭が #の行は無視, 空行は無視 # ^-----5 table_id table開始、数字は欄の数、その後ろは comment # $----- table終了 # This file is in the public domain. ^-----5 PLANET valueが複数欄の場合 # 惑星 日本名 距離 半径 質量 # 億km 千km /Earth Mercury 水星 0.58 2.44 0.06 Venus 金星 1.08 6.05 0.82 Earth 地球 1.50 6.38 1.0 Mars 火星 2.28 3.40 0.11 Jupiter 木星 7.78 71.49 317.83 Saturn 土星 14.29 60.27 95.16 Uranus 天王星 28.75 25.56 14.54 Neptune 海王星 45.04 24.76 17.15 Pluto 冥王星 59.15 1.14 0.01 $----- ^-----2 WEEK valueが単一の場合 # code 曜日 1 日 # Sunday 2 月 # Monday 3 火 # Tuesday 4 水 # Wednesday 5 木 # Thursday 6 金 # Friday 7 土 # Saturday $----- -----$ READ_MTB.DAT ( lines:32 words:128 ) -----------------<cut here tableのブロックを処理しやすくするために、tableの始めと終わり、欄数、id を 持たせています。 こういう形式の fileを読み込むために、次の procedureを 作りました。 引数の proc1,proc2は読み込み時の加工処理が必要なら指定するものです。 -----^ READ_MTB.ICN ( date:98-02-13 time:07:55 ) -----------<cut here ##################### # 変換 table読み込み ##################### # read_mtb.icn 1998/02/13 windy comment修正 # read_mtb.icn 1998/01/18 windy 風つかい H.S. # arg : [1]: f_name: string: filename to read # [2]: c1: cset: 読み込み時の欄区切り文字 # [3]: c2: cset: comment開始文字 # [4]: proc1: procedure: 読み込み時の行毎処理(事前処理) # comment削除 procedure指定を想定。 # [5]: proc2: procedure: 読み込み時の行毎処理((key 以外の部分) # 複数 columnの場合の処理を想定。 # value : record(table,id) # table: table: key:column1 -> value:column2_ # id: string # function : 指定の file(表形式 data)を読み込んで、tableを作成 (generator) # c1で 2分割し 先頭を keyとし、以降を valueにして tableへ格納。 # valueの部分に対して、別 procedureにて加工できる。 # "AAA BBB" -> key: "AAA", value: "BBB" # "AAA BBB CCC" -> key: "AAA", value: "BBB CCC" # tableの先頭 ^-----5 id .... # ↑欄の数 # tableの末尾 $----- # This file is in the public domain. record mtb_read(table,id) # record構成宣言 procedure read_mtb(f_name,c1,c2,proc1,proc2) s_start := "^-----" s_end := "$-----" /c1 := ' \t' # default(space or tab) 欄区切り文字 /c2 := '#' # default comment開始文字 n := 0 # tableの欄の数(兼、table出力中 flag) T := mtb_read() # record生成 dir := open(f_name) | stop("read_mtb: cannot open: ",f_name) # file読み込み while s := read(dir) do { # file読み込み if \proc1 then s := proc1(s,c1,c2,n,T.id) | next # 行毎処理指定があれば # それを実行。 T.idは &nullかも。 s ? { if tab(match(s_start)) then { # table開始 T.table := table() # table生成 n := numeric(tab(upto(c1))) | stop("read_mtb table error: ",s) tab(many(c1)) # T.id := tab(upto(c1) | 0) # table_id next } if match(s_end) then { # table終了 suspend T # table,table_id出力 n := 0 # clear flag T.id := &null # clear table_id next } if n > 1 then { # 有効行(みたい)なら tab(upto(~c1)) column1 := tab(many(~c1)) | next # 第1 column tab(upto(~c1)) column2_ := trim(tab(0),c1) # 第2 column以降 if \proc2 then column2_ :=proc2(column2_,c1,c2,n,T.id) # 行毎処理 # 指定があれば、その処理を行う。 insert(T.table,column1,column2_) # tableへ格納 } } # end of s ? { } # end of while close(dir) end -----$ READ_MTB.ICN ( lines:65 words:296 ) -----------------<cut here sample programです。 2つの tableを読み込んで、list Lに読み込んで tree 形式で内容を表示します。 実際の programでは 各々適当な名前の tableに代入 して、参照 tableとして使います。 -----^ READ_MT2.ICN ( date:98-02-12 time:23:16 ) -----------<cut here #################### # read_mtb.icn の test program #################### # read_mt2.icn 1998/02/12 windy 風つかい H.S. # This file is in the public domain. link read_mtb, # read_mtb table読込み string_e, # split string -> list struct_e # tree_x 構造体 tree表示 procedure main() L := [] # tree表示用 buffer # tableを読み込んで、順に listに格納 every TT := read_mtb("read_mtb.dat",,,del_comment,pla) do { put(L,TT.table) write(TT.id) } tree_x(L) # 構造体 tree表示 end #################### # PLANET部の処理 #################### # arg : [1]: s: string: 対象文字列 # [2]: c1: character: 欄の区切り文字 # [3]: c2: character: commentの始まりの文字 # [4]: n: table欄数(含む key) # [5]: id: table_id # value: string table_idが "PLANET"以外 # record table_idが "PLANET"の場合 record pla_rec(jname,distance,radius,mass) procedure pla(s,c1,c2,n,id) if id == "PLANET" then { # table_idが "PLANET"なら L := split(s,c1) # 欄分割 -> list every i := 2 to 4 do L[i] := numeric(L[i]) # 2番目以降を 数字変換 R := pla_rec ! L # invocation(listを recordへ assign) return R } else return s # table_idが "PLANET"以外なら そのまま end #################### # 行末の comment削除 #################### # arg : [1]: s: string: 対象文字列 # [2]: c1: character: 欄の区切り文字 # [3]: c2: character: commentの始まりの文字 # [4]: n: table欄数(含む key) # [5]: id: table_id # 注 c2が、comment開始以外で使用されているケースには対応していない。 # value: string procedure del_comment(s,c1,c2,n,id) s ? { if match(c2) then fail # 先頭が、c2なら fail(いきなり comment) return tab(upto(c2) | 0) # commentより手前 } end -----$ READ_MT2.ICN ( lines:60 words:212 ) -----------------<cut here 長くなりましたので、残りは次回に。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 華麗なるハープ名演集 / 吉野直子・篠崎史子 (icon420.txt 1998/02/14 PCVAN PIG) ■ Icon > Icon土日夜(21) table読み込み(2) 風つかい 目次 table読み込みの続きです。 動きがちょっとメンドイので、read_mt2と read_mtbの関係を図にしておきます。 (用途に応じて作成) (汎用 procedure) - read_mt2 ----------- -- read_mtb ----------- | main() | | | | table読み込み | | | | ------------------->------->-----> file読み込み | | table,id入手<--------<--- | read_mtb() | | list Lに格納 | | | table区切り検出 | | id表示 | | | id取り出し | | (tableがあれば繰返し)| | | 欄数取り出し | | Lを tree表示 | | | 1行読み込み | | -------------------- | | | 読み込み時の加工 | | comment削除 <--------<-------<---------- proc1()を呼ぶ | | del_comment() | | | | | ----------------->------->----------> 加工後 data | | | | | key/value分割 | | -------------------- | | | valueを加工 | | 欄分割、等 <--------<-------<---------- proc2()を呼ぶ | | pla() | | | | | ----------------->------->----------> 加工後 data | | | | | tableへ格納 | | | | | (table末尾迄繰返し)| | | ---<-------- table,idを返す | | | | (tableがある限り | | | | 繰り返し)| ---------------------- ----------------------- 動かした結果です。 -----^ READ_MT ( date:98-02-12 time:23:44 ) ----------------<cut here PLANET WEEK <list 1> + <table 1> | + <pla_rec 7> <- string "Uranus" | | + string "天王星" | | + real 28.75 | | + real 25.56 | | + real 14.54 | + <pla_rec 1> <- string "Mercury" | | + string "水星" | | + real 0.58 | | + real 2.44 | | + real 0.06 | + <pla_rec 5> <- string "Jupiter" | | + string "木星" | | + real 7.78 | | + real 71.49 | | + real 317.83 | + <pla_rec 2> <- string "Venus" | | + string "金星" | | + real 1.08 | | + real 6.05 | | + real 0.82 | + <pla_rec 6> <- string "Saturn" | | + string "土星" | | + real 14.29 | | + real 60.27 | | + real 95.16 | + <pla_rec 3> <- string "Earth" | | + string "地球" | | + real 1.5 | | + real 6.38 | | + real 1.0 | + <pla_rec 8> <- string "Neptune" | | + string "海王星" | | + real 45.04 | | + real 24.76 | | + real 17.15 | + <pla_rec 4> <- string "Mars" | | + string "火星" | | + real 2.28 | | + real 3.4 | | + real 0.11 | + <pla_rec 9> <- string "Pluto" | + string "冥王星" | + real 59.15 | + real 1.14 | + real 0.01 + <table 2> + string "火" <- string "3" + string "木" <- string "5" + string "月" <- string "2" + string "土" <- string "7" + string "水" <- string "4" + string "日" <- string "1" + string "金" <- string "6" -----$ READ_MT ( lines:57 words:291 ) ----------------------<cut here 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 華麗なるハープ名演集 / 吉野直子・篠崎史子 (icon421.txt 1998/02/14 PCVAN PIG) ■ Icon > Icon土日夜(22) 構造体 copy 風つかい 目次 昨日、今日と 暖かい天気が続いています。今日は結構 強い南風でしたので、 春一番かな。 さて、今回は、構造体の copyです。多分、今まで使っていないと思います。 では、通常の代入はコピーじゃないのかというと、違うんですね。 例えば、list L を生成しておいて、それを LLへ代入します。 Lの要素を変更すれば LLの要素も変更されますし、LLの要素を変更すれば Lの 要素も変更されています。 試しにやってみますと、 -----^ COPY01.ICN ( date:98-02-14 time:17:25 ) -------------<cut here #################### # copyの test program #################### # copy01.icn Rev.1.1 1998/02/14 windy 風つかい H.S. # This file is in the public domain. procedure main() L := ["AA","BB","CC"] # list Lを生成 LL := L # Lを LLへ assign writes("LL: ") ; every writes(" ",!LL) ; write() # LLの要素を書き出し L[1] := "XX" # 元の Lの第1要素を変更 writes("LL: ") ; every writes(" ",!LL) ; write() # LLの要素を書き出し LL[2] := "YY" # LLの第2要素を変更 writes("L: ") ; every writes(" ",!L) ; write() # Lの要素を書き出し end -----$ COPY01.ICN ( lines:14 words:78 ) --------------------<cut here 結果は、こうなります。 -----^ COPY01 ( date:98-02-14 time:17:26 ) -----------------<cut here LL: AA BB CC LL: XX BB CC L: XX YY CC -----$ COPY01 ( lines:3 words:12 ) -------------------------<cut here これは、Lも LLも同じ listを示しているためです。 ("XX"へ変更) L[1] L[2] L[3] ↓ ↓ ↓ +------+ +------+ +------+ L--------> | "AA" |----| "BB" |----| "CC" | ---> +------+ +------+ +------+ / ↑ ↑ ↑ (LL := L) LL -- LL[1] LL[2] LL[3] ("YY"へ変更) procedure の引数として、構造体を指定した時も同様です。 recordを使って試してみます。 -----^ COPY02.ICN ( date:98-02-14 time:22:31 ) -------------<cut here #################### # copyの test program #################### # copy02.icn Rev.1.2 1998/02/14 windy copy_2引数修正(分かり易くするため) # copy02.icn Rev.1.1 1998/02/14 windy 風つかい H.S. # This file is in the public domain. record copy_test(aaa,bbb,ccc) procedure main() R := copy_test("AA","BB","CC") # record R を生成 writes("R: ") ; every writes(" ",!R) ; write() # R の要素を書き出し copy_2(R) writes("R: ") ; every writes(" ",!R) ; write() # R の要素を書き出し end procedure copy_2(RR) RR.aaa := "ZZ" return end -----$ COPY02.ICN ( lines:19 words:69 ) --------------------<cut here copy_2()の内部で、要素を変更すると、main()で見ても 変更されています。 -----^ COPY02 ( date:98-02-14 time:22:32 ) -----------------<cut here R: AA BB CC R: ZZ BB CC -----$ COPY02 ( lines:2 words:8 ) --------------------------<cut here 図にするとこんな具合です。 R.aaa R.bbb R.ccc main() ↓ ↓ ↓ ↑ R ------> +------+ +------+ +------+ ==================== | "AA" |----| "BB" |----| "CC" | ↓ RR ------> +------+ +------+ +------+ copy_2() ↑ ↑ ↑ RR.aaa RR.bbb RR.ccc ("ZZ"へ変更) このように要素自体はコピーしないという仕様は、構造体を使うとメモリーを 沢山 消費するので、なるべく避けるためだそうです。 copy関数は、要素自体も実際にコピーして、別の要素にしたい場合に使います。 setを使って試してみます。 -----^ COPY03.ICN ( date:98-02-15 time:12:47 ) -------------<cut here #################### # copyの test program #################### # copy03.icn Rev.1.2 1998/02/15 windy 説明の都合で修正 # copy03.icn Rev.1.1 1998/02/14 windy 風つかい H.S. # This file is in the public domain. procedure main() S := set(["AA","BB","CC"]) # set Sを生成 S2 := S # Sを S2へ assign S3 := copy(S) # Sの複製を作成し、S3へ assign delete(S3,"AA") # S3から "AA"を削除 writes("S: ") ; every writes(" ",!S) ; write() # S の要素を書き出し writes("S2: ") ; every writes(" ",!S2) ; write() # S2の要素を書き出し writes("S3: ") ; every writes(" ",!S3) ; write() # S3の要素を書き出し end -----$ COPY03.ICN ( lines:15 words:84 ) --------------------<cut here Sを copyした S3を変更しても Sや S2はかわりません。 -----^ COPY03 ( date:98-02-15 time:12:47 ) -----------------<cut here S: AA CC BB S2: AA CC BB S3: CC BB -----$ COPY03 ( lines:3 words:11 ) -------------------------<cut here 図にするとこうなります。 +-- set ---------------------------+ S ------> | +------+ +------+ +------+ | | | "AA" | | "BB" | | "CC" | | (S2 := S) S2 ------> | +------+ +------+ +------+ | +----------------------------------+ +-- set ---------------------------+ S3 ------> | +------+ +------+ +------+ | (S3 := copy(S)) | | "AA" | | "BB" | | "CC" | | | +------+ +------+ +------+ | +----------------------------------+ (↑"AA"を削除) copyは、構造体を programの中で使っていて、構造体の要素を変更しても、変更前 の状態を保存しておく必要がある時に使います。 しかし、入門講座では、今まで使ったことはありません。殆どの場合に使わなくとも すませられるみたいです。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 華麗なるハープ名演集 / 吉野直子・篠崎史子 (icon422.txt 1998/02/14 PCVAN PIG) ■ Icon > Icon土日夜(23) 引用符 風つかい 目次 昨日は、暖かだったんですが 今日は一転して 雪が降っていました。来週から コートが脱げるかな? なんて思っていたんですが。 さて、今日は、引用符(quotation mark)の関係を。 通常、英文では、" や ' で 文字列処理をくくるやるです。 文字列処理をしていて、引用符でくくってあると 特別な処理をするケースがあります。 Icon入門講座4の Icon迷い道(7)で CSV(comma separated value)を表に変換 するところで、文字列 dataを " で くくってあるのを 処理しました。 結構、メンドイんですよね。 くくってあるだけなら両端の " を除けばいいので すが、文字列中に 文字として " 自体が 出てきたときの扱いが面倒で。 今回は それより簡単で 引用符でくくってある部分 を無視して 特定文字の位置 を見つけるものです。 -----^ QUOTE01.ICN ( date:98-02-15 time:22:33 ) ------------<cut here #################### # 引用符で囲まれた文字列 を無視する処理 #################### # quote01.icn Rev.1.1 1998/02/15 windy 風つかい H.S. # This file is in the public domain. link struct_e # scale procedure main() s := "ABCDE\'ABCDE\'ABCDE\'ABCDE\'" scale(s) s ? every write(qq_upto('A')) s ? write(qq_upto('Z') | "no such a position") write() s := "ABCDE\'ABCDE\'ABCDE\'ABCDE\'ABCDE\'ABCDE" scale(s) s ? every write(qq_upto('A')) s ? write(qq_upto('Z') | "no such a position") write() s := "ABCDE\'A\'\'BCDE\'ABCDE\'ABCDE\'ABCDE\'ABCDE" scale(s) s ? every write(qq_upto('A')) s ? write(qq_upto('Z') | "no such a position") end #################### # 引用符で囲まれ無い部分を対象にした upto #################### # arg: [1]: 検索対象 cset # [2]: 引用符 cset # [3]: string # value: integer (文字位置) # 引用符を表わすのに、引用符2つ続ける方式に対応している。 # 日本語対応は、していない。 procedure qq_upto(c1,c2,s) /s := &subject # default /c2 := '\"\'' # default s ? { # sを走査対象として while tab(ps := upto(c1 ++ c2)) do { # 探している文字か 引用符だったら if any(c1) then { # 探している文字だったら suspend ps # 文字位置を返す move(1) # 1文字 skip } else { # 引用符だったら c_quote := move(1) # 1文字 skip while tab(upto(c_quote)+1 | 0) do { # 引用部を skip #↑ 引用符が閉じていないケースだが... if not any(c_quote) then break # 引用文字以外なら else move(1) # 引用符だったら、引用符自体を表わして } # いるので、引用状態を継続 } } } end -----$ QUOTE01.ICN ( lines:53 words:184 ) ------------------<cut here 動かした結果です。 -----^ QUOTE01 ( date:98-02-15 time:22:34 ) ----------------<cut here 0000000001111111111222222 1234567890123456789012345 ABCDE'ABCDE'ABCDE'ABCDE' 1 13 no such a position 000000000111111111122222222223333333 123456789012345678901234567890123456 ABCDE'ABCDE'ABCDE'ABCDE'ABCDE'ABCDE 1 13 25 no such a position 00000000011111111112222222222333333333 12345678901234567890123456789012345678 ABCDE'A''BCDE'ABCDE'ABCDE'ABCDE'ABCDE 1 15 27 no such a position -----$ QUOTE01 ( lines:22 words:29 ) -----------------------<cut here ついでに、文字列から、引用符で囲まれた 以外の 空白を削除する procedure も作ってみました。 -----^ QUOTE02.ICN ( date:98-02-15 time:22:33 ) ------------<cut here #################### # 引用符で囲まれた 以外の空白を削除 #################### # quote02.icn Rev.1.1 1998/02/15 windy 風つかい H.S. # This file is in the public domain. link struct_e # scale procedure main() s := "A C E \'A C E\'AB E\' C \' CDE" scale(s) s ? write(qdel_space()) end #################### # 引用符で囲まれた部分以外の空白を削除 #################### # arg: [1]: 引用符 cset # [2]: string # value: string # 日本語対応していない。(SJISでは、2byte目に引用符が現れるケース) procedure qdel_space(c,s) /s := &subject /c := '\"\'' ss := "" s ? { while ss ||:= tab(upto(' ' ++ c)) do { if any(' ') then { # 空白だったら tab(upto(~' ')) # 空白以外迄 skip } else { # 引用符だったら ss ||:= move(1) # 1文字(引用符)を 足しこみ ss ||:= tab(upto(c)+1 | 0) # 引用部を 足しこみ #↑ 引用符が閉じていないケースだが... # その部分は無視しよう。 } } ss ||:= tab(0) # 残りを足しこみ return ss } end -----$ QUOTE02.ICN ( lines:40 words:129 ) ------------------<cut here 結果です。 -----^ QUOTE02 ( date:98-02-15 time:22:34 ) ----------------<cut here 0000000001111111111222222222233 1234567890123456789012345678901 A C E 'A C E'AB E' C ' CDE ACE'A C E'ABE' C 'CDE -----$ QUOTE02 ( lines:4 words:17 ) ------------------------<cut here 日本語対応も 以前紹介しました SJIS対応 procedureを使えば できます。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: Je'laime チェンバロに恋して / 曽根麻矢子 (icon423.txt 1998/02/15 PCVAN PIG) ■ Icon > Icon土日夜(24) Windows Icon 9.3.1 風つかい 目次 comp.lang.iconに、Windows95/NT版 Iconの新バージョンのアナウンスが、 流れていましたので、ご紹介します。 本体機能は、Ver9.3と変わっていないようですが、インストーラやヘルプ が充実してきました。 サイズは zipファイルで、4M あります。 ftp://ringer.cs.utsa.edu/pub/icon/nt/binaries/ に置いてあります。 README 489 bytes Wed Nov 26 06:19:00 1997 winicon.zip 4085 Kb Wed Nov 26 06:14:00 1997 Zip Compressed Data この zipファイルと解凍しますと、次のようなファイルが現れます。 DATA AR 508,651 97-11-26 5:50 DATA.AR GIPL AR 1,302,489 97-11-26 5:50 GIPL.AR IPL AR 1,139,927 97-11-26 5:50 IPL.AR README TXT 2,968 97-11-26 5:50 README.TXT SETUP CFG 1,458 97-11-26 5:50 SETUP.CFG SETUP EXE 105,744 97-11-26 5:50 SETUP.EXE TROUBLE TXT 1,557 97-11-26 5:50 TROUBLE.TXT UNINSTAL CFG 494 97-11-26 5:50 UNINSTAL.CFG UNINSTAL EXE 60,464 97-11-26 5:50 UNINSTAL.EXE WINICON AR 1,242,933 97-11-26 5:50 WINICON.AR 10 個 4,366,685 バイトのファイルがあります この中の setup.exeを実行すれば、インストールされます。 やってみますと、34M位HDDを食いました。 PC/ATコンパチマシンなら、問題なくインストールできますが、 98マシンの場合で、 A: または B: ドライブにインストールしようとすると、 どうも HDDを FDDと勘違いするみたいで、diskを入れろと催促されてインス トールでません。 作者の Jeffery教授に問い合わせたところ、とりあえず細工してくれとのことで、 setup.exeと同じディレクトリーに THISDISK というファイル名で、 インストーラが聞きに来る度に、順に、 ------最初は DiskNumber=1 NextDiskNumber=2 ------次は DiskNumber=2 NextDiskNumber=3 ------次は DiskNumber=3 NextDiskNumber=4 ------次は DiskNumber=4 ------ と置いてあげて、イントーラをだましてあげると良いとのことで、やったら うまくいきました。 >From: jeffery@ringer.cs.utsa.edu (Clinton L. Jeffery) >Newsgroups: comp.lang.icon >Subject: Windows Icon 9.3.1 release announcement >Date: 26 Nov 1997 06:38:58 -0600 >Organization: University of Texas at San Antonio >Lines: 25 >Distribution: inet >Message-ID: <65h592$jp8@pandora.cs.utsa.edu> > > >The Microsoft Windows distribution of Version 9.3.1 of the Icon Programming >Language is available from ftp://ringer.cs.utsa.edu/pub/icon/nt/binaries/ > >This release corresponds to the forthcoming graphics book, described at >www.cs.arizona.edu/icon/. Windows Icon programmers will all want this >release because of: > >* standard Windows installation (and uninstallation) via a setup.exe file >* creation of a program group and program items for launching Windows Icon >* bundling of console-mode (non-graphics) binaries for NT and Win95 >* improved functionality of the integrated development environment, Wi >* comprehensive on-line documentation in keyword-searchable Windows Help > format, including the Icon Program Library and VIB interface builder >* vastly improved support for Windows 3.1/Win32s users >* performance improvements in tasks such as reading image files >* bug fixes > >Windows Icon will continue to evolve, but this is a major milestone and I >would greatly appreciate positive or negative feedback, suggestions, and bug >reports if you use this software. >-- >Clint Jeffery >jeffery@cs.utsa.edu >The University of Texas at San Antonio 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 全部だきしめて/Takuro Yoshida & LOVE2 ALL STARS (icon424.txt 1997/12/05 PCVAN PIG) ■ Icon > Icon土日夜(25) Icon Newsletter No.54 風つかい 目次 Iconの Newsletter No.54が、Icon-WEBに、掲載されましたので、お知らせ します。 URLは、次の通りです。 http://www.cs.arizona.edu/icon/inl/inl54/inl54.htm 目次を引用しておきます。 No. 54 -- December 1, 1997 Contents The Curse of DOS New Icon Program Library Release Status of the Graphics Book Unicon Chinese Icon Book From Our Mail Updated Icon Web Site Icon Mirror Site Using Icon to Spin the Web An Introduction to Wi 目次の中にも出ていますが、Program Libraryが更新されています。 次のところから FTPできます。 BIPLが基本 Libraryで、GIPLがグラフィック Libraryです。 機種対応にいろいろな圧縮形式を用意してあります。 ftp://ftp.cs.arizona.edu/icon/library Index of /icon/library Name Last modified Size bipl.hqx 02-Dec-97 20:43 1.9M 基本 Library bipl.taz 02-Dec-97 17:20 1.7M bipl.tgz 02-Dec-97 17:20 1.2M bipl.zip 02-Dec-97 17:20 1.4M gipl.hqx 02-Dec-97 20:43 1.5M Graphic Library gipl.taz 02-Dec-97 17:20 2.7M gipl.tgz 02-Dec-97 17:20 1.9M gipl.zip 02-Dec-97 17:20 1.0M info.hqx 02-Dec-97 20:43 63K info.taz 02-Dec-97 17:20 39K info.tgz 02-Dec-97 17:20 30K info.zip 02-Dec-97 17:20 17K mipl.hqx 02-Dec-97 20:43 109K mipl.taz 02-Dec-97 17:20 191K mipl.tgz 02-Dec-97 17:20 112K mipl.zip 02-Dec-97 17:20 69K README 02-Dec-97 17:25 1K 18 files 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: 全部だきしめて/Takuro Yoshida & LOVE2 ALL STARS (icon425.txt 1997/12/05 PCVAN PIG) ■ Icon > Icon土日夜 むすび 風つかい 目次 秋の夜長から 始めた Icon土日夜 ですが、冬も過ぎ 春はすぐそこ となりました ので、このへんで おしまいとします。 今回の入門講座をやっての収穫は、record ですね。 Icon教典 (The Icon Programming Language)には、勿論 載っているんですが、 こんなに便利なものとは、思っていませんでした。 というか、何に使うんだろう? と、思っていました。 ・listは、本を読めば、便利さはすぐ分かります。 recordは、listの要素指定を分かりやすくするもので、深い階層の listを listを使い始めないと、便利さは分からないみたいです。 ついでに言うと、 ・generatorの便利さも、これまた 使ってみないと分かりません。 back trackingだけにしか 使えないのか と思っていましたが、使い始める と はまります。 未だ未だ、他にも Iconの便利な機能を、知らないでいると 思います。 例えば、講座で、未だ取り上げていない関数に、bal()をいう関数があります。 数式処理に威力を発揮するらしいのですが、理解できていません。 このあたりを 使いこなすと、テキスト【解析】らしくなるのかな? と思って います。 で〜、入門講座は、未だ未だ続きますが、Icon土日夜 は このへんで。 ところで、Icon関係の fileを libraryに uploadしていますが、先日 download 総計が 1000件を越えました。 入門講座を読んだり Iconを試して頂ける方が増えますと やはり励みになります。 ありがとうございます。 <1998/02/11> PIG SLABO FPL FGALTS file計 BIPL.LZH - 15 - 37 52 DE386.LZH - 19 - 104 123 ICONLEC4.LZH 1 6 13 33 53 ICONLEC3.LZH 3 13 29 113 158 ICONLEC2.LZH 5 17 67 129 218 ICON_LEC.LZH 7 35 124 231 397 ------------------------------------------------ SIG/forum計 16 105 233 647 1001 そうそう、Icon-WEBに Icon Projectのメンバーが紹介されていました。 http://www.cs.arizona.edu/icon/iconproj/iconproj.htm で、メンバーの顔がご覧になれます。 風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp) < IconのWWWは、http://www.cs.arizona.edu/icon/index.html> BGM: ECHO / 遊佐未森 (icon426txt 1998/02/18 PCVAN PIG)