Icon入門講座 1996/12/8 風つかい --- AWKerのためのIcon入門 --- (TRA11936@pcvan.or.jp) (PFF01531@niftyserve.or.jp) ■ Icon > Icon入門講座なんぞをはじめようかな 風つかい 近頃、2行以上のスクリプトを書く必要がある場合は、awkの替わりに Icon (アイコン)というテキスト処理言語を使っています。 sed や awk の1行野郎で済むものは、sed, awk ですましますが、ちょっと 頭をひねる必要のあるものは、Iconで書いています。 Iconは、なかなかユニークな特徴を持った言語で、もっと使われていいので はと思いますが、vanやnifのテキスト処理の会議室ではあまり話題には 上っていません。 興味をもたれる人が増えるといいなということで、私も使いこなせている訳 ではありませんが、入門講座なんぞをはじめてみようかと思います。 awk との比較みたいなかっこうで説明できるといいんですけれど、どうなる ことやら。 尚、Iconは PDSですので、私の文章もならって転載・編集等(そんな人い るかいな?)自由とします。 目次 第1回 Iconって何? 1.Iconって何? 2.Iconってフリーソフト? 3.資料はありますか? 第2回 Iconの入手方法は? 1.取り敢えずIconを動かしてみたい。 2.hello worldはどうやって動かすの? 第3回 Iconの特徴は?(1) 1.Iconの特徴は? 1)テキスト解析言語とでも 2)awkの処理の基本 第4回 Iconの特徴は?(2) 3)テキストファイルの読み込み 第5回 Iconの特徴は?(3) 4)パターンマッチの考え方 5)データ構造 第6回 Iconの特徴(4)制御構造 6)プログラム制御構造 第7回 Iconの特徴(5)スキャン 7)文字列走査 第8回 Iconの特徴(6)スキャン(続) 8)文字列走査(続) 第9回 データ構造 set 第10回 データ構造 list 第11回 データ構造 table 第12回 procedure/scope 第13回 prpcedure/scopeサンプル 第14回 type変換、他 第15回 エスケープ文字、他 第16回 wild.icn 第17回 Test Driver for wild 第18回 iyab.icn 第19回 vanlog.icn 第20回 むすび。 風つかい (TRA11936@pcvan.or.jp) (icon_00.txt) ■ Icon > Icon入門講座(1) Iconって何? 風つかい 目次 1.誰が作ったの? Icon(アイコン)は、米国アリゾナ大学のGriswold教授(のグループ) が、コンピュータ研究の際に作った、テキスト処理に重点をおいたプログ ラム言語です。 そして現在もGriswold教授のグループでサポートされています。 Griswold教授は、SNOBOL(スノーボウル)という強力なテキスト処理言 語をその前に作って作っています。(私は使ったことは無いのですが。) しかし、SNOBOLは今風の構造化プログラム対応ではないので、とっつ きにくいため、全面的に作り替えたというふうなことをおっしゃっていま す。 今は、テキスト処理結果をグラフィック化処理して分かりやすく見 せための機能拡張が行われつつあります。 Griswold教授は、学生へのプログラミング教育の教材にも使われていま す。 アリゾナ大学には、Icon言語のサポートグループ(icon-project)があり ます。質問等は、icon-project@cs.arizona.edu に送ると答えてもらえます。 (勿論、英語でないと分からないと思いますが。) 2.Icon ってフリーソフト? Iconは、Griswold教授(とそのグループ)が行っている研究の副産物と いうことで、PDS(Public Domain Software)とされています。 実行形式と共に、ソースファイルも公開されています。またライブラリー も公開されています。 誰でも、自由に使用や配布をして良いし、またソースをいじって、機能 追加・変更等を行ってもかまわないということです。 ということで、フリーソフトの細かい定義は別として、フリーソフトと いうことです。 尚、icon-projectはアリゾナ大学としては非公式な組織の扱いとなって いるそうです。 3.資料はありますか? 1)WWW icon-project では、WWWでIconの情報を公開しています。ここで殆ど全て の情報(と情報源)がわかります。 urlは http://www.cs.arizona.edu/icon です。 ここがIconのメインメニューとなっていまして、更に ・プロジェクト状況 ・入門ドキュメント ・プログラム ・ライブライリー ・ドキュメント 等を見たり、ファイルを入手したりできます。 メニュー次に載せます。(96/11下旬頃のもの) The Icon Programming Language Icon is a high-level, general-purpose programming language with a large repertoire of features for processing data structures and character strings. Icon is an imperative, procedural language with a syntax reminiscent of C and Pascal, but with semantics at a much higher level. Book Sale! Status Report Language Information Dave Hanson's Brief Introduction John Shipman's Tutorial An Overview Reference Information Programming Corner Implementations Versions Version 9.1 FTP Area for Binaries FTP Area for Source Program Library Indexes Technical Report Submission Guidelines FTP Area Documentation Frequently Asked Questions Technical Reports The Icon Newsletter The Icon Analyst Third Edition of the Icon Language Book Graphics Book Other Documents 2)本 The Icon Programming Language という本が発行されています。 現在は第2版を購入できます。 今は第3版の発行準備中です。予定は今年の11月中旬となっていますが 今日現在のところ発行されたというアナウンスはありません。 (1996/12/6付けの status report では印刷中となっています。もう注文できる みたいです。 追記1996/12/7) 3)Newsletter Newsletterが年2回発行されています。 以前はもっと頻度が高かったのです が、WWWで情報公開できるようになったので、回数が削減されてきています。 (そのうち無くなるかも?) NewsletterもWWWにて、公開されているため、現在はWWWが無い環境の方のため という意味合いになってきています。 (WWWが以前は郵送料も含め無料だったのですが、今は有料。といっても印刷代 +郵送料程度。) 4)Icon Analyst 年6回、プログラミングテクニックとか応用とかについて技術サポート 資料が発行されています。(有料。と言っても印刷費+郵送料程度) 尚、どんなものか試してみるだけなら、WWWから手に入る資料で十分です。 じゃ、第1回はこの辺で。(後が続くのだろうか?) 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) (icon_01.txt) ■ Icon > Icon入門講座(2) Iconの入手方法は? 風つかい 目次へ 1.Icon(アイコン)を、とりあえず動かしてみたいが? Iconは色んなマシン上で動きますが、Windows3.1/95の DOS窓で動くもの(386バージョン)を入手するとして説明します。 (私がこのバージョンしか動かしたことが無いもので....) 1)パッケージの入手 ・ftp://ftp.cs.arizona.edu/icon/packages から入手できます。 そこに使用環境毎のディレクトリーがあります。 acorn 13-Jun-96 13:43 - amiga 22-Jun-96 16:17 - atari 21-Mar-96 00:00 - macintosh 21-Mar-96 00:00 - msdos 24-Mar-96 00:00 - mvs 24-Apr-96 00:00 - os2 21-Mar-96 00:00 - README 20-Mar-96 00:00 1K unix 21-Mar-96 00:00 - vms 21-Mar-96 00:00 - で、ここで、msdosを選ぶと 9.0 24-Mar-96 00:00 - de.lzh 24-Mar-96 00:00 339K de386.lzh 24-Mar-96 00:00 264K ds.lzh 01-Mar-96 00:00 1.4M README 24-Mar-96 00:00 1K と、msdos用のファイルが現れますので de386.lzhを選んでダウンロードします。 (その他の環境の方は該当の機種のディレクトリーから入手して下さい。 尚、msdosでEMS無しの環境の方は、de.lzhです。 また、1.4Mの大きなds.lzhはCで書かれたソースファイルです。) 圧縮に吉崎さんのLHAを使ってくれているのを見るとうれしいですね。 日本のフリーソフトが世界で使われているのだと実感できます。 2)ファイルの解凍 ・ファイルの拡張子がLZHですので、LHAで解凍して下さい。 ・すると以下のファイルができます。これをまた解凍します。 Listing of archive : DE386.LZH Name Original Packed Ratio Date Time Attr Type CRC -------------- -------- -------- ------ -------- -------- ---- ----- ---- DOCS.LZH 23078 23078 100.0% 96-03-24 08:58:46 a--w -lh0- 593D ICON.LZH 245336 245336 100.0% 96-03-24 08:14:40 a--w -lh0- 0A1A README 1069 587 54.9% 96-03-24 08:17:08 a--w -lh1- 84A2 SAMPLES.LZH 1456 1448 99.5% 96-03-24 08:10:44 a--w -lh1- D10E -------------- -------- -------- ------ -------- -------- 4 files 270939 270449 99.8% 96-05-06 00:02:38 ・DOCS.LZHからは、ドキュメントがでてきます。 (英文です。はい。) ・IPD248 :MSDOS 32ビット版の使い方 ・IPD266 :Icon Ver9.1の概要 ・IPD267 :Ver8.0からの変更内容 ・IPD46 :トラブルレポート用紙 Listing of archive : DOCS.LZH Name Original Packed Ratio Date Time Attr Type CRC -------------- -------- -------- ------ -------- -------- ---- ----- ---- IPD248.DOC 11950 4875 40.8% 96-03-24 08:57:52 a--w -lh1- D0F9 IPD266.DOC 19190 7364 38.4% 96-03-24 08:57:54 a--w -lh1- 4621 IPD267.DOC 26971 10259 38.0% 96-03-24 08:57:56 a--w -lh1- 91A0 IPD46.DOC 786 444 56.5% 96-03-24 08:57:56 a--w -lh1- 580D -------------- -------- -------- ------ -------- -------- 4 files 58897 22942 39.0% 96-03-24 08:58:46 ・ICON.LZHからは、 ・icont.exe :Iconのコンパイラ(中間言語への変換) ・iconx.exe :実行モジュール(中間言語インタープリータ) が、でてきます。 Listing of archive : ICON.LZH Name Original Packed Ratio Date Time Attr Type CRC -------------- -------- -------- ------ -------- -------- ---- ----- ---- ICONT.EXE 144097 78446 54.4% 96-03-24 08:13:28 a--w -lh1- 4CAD ICONX.EXE 291422 166823 57.2% 96-03-24 08:13:30 a--w -lh1- 0B06 -------------- -------- -------- ------ -------- -------- 2 files 435519 245269 56.3% 96-03-24 08:14:40 ・SAMPLES.LZH からは、サンプルプログラムがでてきます。 Listing of archive : SAMPLES.LZH Name Original Packed Ratio Date Time Attr Type CRC -------------- -------- -------- ------ -------- -------- ---- ----- ---- CROSS.ICN 700 362 51.7% 85-09-08 05:54:04 a--w -lh5- 085D HELLO.ICN 85 61 71.8% 86-09-28 00:24:08 a--w -lh5- 3952 MEANDER.ICN 803 394 49.1% 85-09-10 15:02:26 a--w -lh5- 1D26 ROMAN.ICN 612 343 56.0% 85-09-08 05:54:44 a--w -lh5- 25F4 CROSS.DAT 56 52 92.9% 85-09-08 05:55:08 a--w -lh5- 97B0 MEANDER.DAT 23 23 100.0% 85-09-10 15:02:40 a--w -lh0- C092 -------------- -------- -------- ------ -------- -------- 6 files 2279 1235 54.2% 96-03-24 08:10:44 hello.icn が、よくある hello world プログラムです。 Iconのプログラムは拡張子にicnを使います。 2.hello world はどうやって動かすの? サンプルの中のhello.icn は次のようなものです。 バージョン表示、対象ホスト表示と hello world を表示するものです。 -----^ HELLO.ICN ( date:86-09-28 time:00:24 ) --------------<cut here procedure main() write(&version) write(&host) write("hello world") end -----$ HELLO.ICN ( lines:5 words:7 ) -----------------------<cut here awk との比較でいいますと、 ・print が write になっていて、 ・プログラム全体は procedure と endでくくられている。 ・&version と &host はキーワード(Iconプログラム自体が持つ定数) (awk には相当のものはありません) このファイルを icont.exe を使ってコンパイルすると実行モジュールが できます。 icont.exeにパスが通っている環境で、コマンドラインから icont hello.icn とすると hello.exe ができます。 このexeファイルは、白鷺で処理した awkスクリプトと 同じやりかたで作成したexeファイルと考えて下さい。 (ファイルの先頭で、iconxを呼んで後続するスクリプト(iconの場合は 中間言語コード)を引数として実行させる方式) iconx.exeにパスが通っている環境で、 hello > hello.txt を実行しますと、結果は次のようになります。 -----^ HELLO.TXT ( date:96-11-17 time:01:47 ) --------------<cut here Icon Interpreter Version 9.1. November 21, 1995 PC 386 in 32-bit protected mode ex Watcom C/389 9.0 hello world -----$ HELLO.TXT ( lines:3 words:19 ) ----------------------<cut here じゃ、第2回はこの辺で。(後が続くのだろうか?) 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) (icon_02.txt) ■ Icon > Icon入門講座(3) Iconの特徴は?(1) 風つかい 目次へ あれれ、ヘッダーを間違えていましたね。 Iocn じゃなくて Icon です。 ~~ ~~ (追記: 当初ヘッダーのIconの綴りを間違えていたのです。) 両手でタイプしていると、右手と左手の同期がとれなくて、字が入れ違って しまうのが良くあります。 というか、左手が遅いので、右手で打つ次の文字 が先に来てしまうんですね。 それをまたコピーして使うと軒並み間違ってしまうんですね〜。 ま、いっか。 Icon入門講座の方はつづりが合っていたので。 Iconって何なんだと聞かれてましたが、なんといったらいいんでしょうね〜。 テキストデータ処理の中でも、【テキスト解析言語】とでもいったらいいの かな〜?。 ヘッダーの間違いだけで書き込むのもナンですので、 次の週末に予定して いた分からのうち少し書いてアップしましょう。 さて、第3回です。 1.Icon(アイコン)の特徴は何? 1)テキスト(文章)解析言語とでも Iconは、テキストデータ処理の中でも、テキスト(文章・文書)解析 向けに考えられたようです。 文章が、どういう構成になっているかなんかの解析(構文解析)は得意 の分野です。(でも私はその辺が良くは理解できていませんので...) 2)awk の処理の基本 まず、awk と比較できるところから説明したいので、 awkの処理の基本 事項をあげてみます。 (1) 1行づつ awkが、テキストファイル(デフォルト:標準入力) から読み込んで (2) その行を awkが、FS(Field Separater)に従って、分割し $1,$2,...へセットしてくれる。 $0へは、行全体がセットされる。 (3) スクリプトにて、$0,$1,$2...に対するマッチングパターンを 指定し、一致が取れたとき(/取れないとき)のアクション 指定する。 (4) マッチングパターン指定には、正規表現を使う。 (5) 組み込みデータ構造としては、連想配列がサポートされている。 (6) プログラム制御構造としては、 ・順次処理 ・・・順番にという当たり前の処理 ・if ... then ... else ・while ・for ・do ・&& ・|| ・ユーザー関数 ・組み込み関数 というようなところでしょうか。 この中で、連想配列は、うまく使うとプログラムとても簡潔になり、 世の中に、こんなにすばらしいものがあったのだ!。と【感動】した 覚えがあります。 今日、AWK についてあんましうろ覚えで書くのもナンだからと AWK教典 (プログラム言語 AWK)を読み返していましたら、エピローグのところ に、連想配列はSNOBOLの表から思い付いたと書いてありました。 ふむ、ふむ。だから、awk にも、Iconにも連想配列(Iconではテーブル) があるんだと納得しました。 この後に、Iconとの違いを書く予定ですがそれは、週末に... ほんじゃ、第3回はこの辺で。 (後が続くのだろうか? ・・・酒とタバコと音楽さえあれば...) 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 愛よりも激しく、誰よりも愛しく/Favorite Blue BGD: 薩摩白波5:5お湯割り <- D: Drink BGS: Mild Seven Menthol <- S: Smoke (icon_03.txt) ■ Icon > Icon入門講座(4) Iconの特徴は?(2) 風つかい 目次へ ううっ。また、前回の講座で、1か所Iocnになっていた。 ・・・と嘆きつつも、メゲずに第4回です。 (追記 このテキストでは、もう直っています。) 週1のペースでは、今年中に終わりそうもないので、少しペースをあげます。 前回あげた awkの処理の基本項目について、Iconとの違いをみていきましょう。 いずれの項目も 幾ばくか...大幅か...程度は色々ですが、違いがあります。 3)テキストファイルの読み込み awkで処理対象のテキストファイルを読み込むとすると、コマンドラインから (1) jgawk -f nantara.awk kantara.txt とするか (2) jgawk -f nantara.awk < kantara.txt とすれば awk は賢く、kantara.txtを1行づつ読み込んで、nantara.awkで処理しやすい ように、その行を、FS(Field Separater デフォルト:" ")の指定に従って、 欄(カラム)へ分解し、$1〜$nにセットしてくれます。 で、Iconでは、 nantara.icn をコンパイルした、nantara.exeがあったとします。 (2)のように、 natara < kantara.txt とやれば、nantara.icnで処理でき ます。(nantara.icnにファイル読み込み関数を使うのですが。) しかし、(1)のようにコマンドラインパラメータ指定しても自動的には読み込 みは行われません。(nantara.icnの中でコマンドラインパラメータを解析し てファイルオープン手続きを行えば可能なのですが。) 更に、読み込んだ行を走査して自動的に欄に分解するような事もしません。 で・・・、自分でやるのです。そのための行解析の手段が提供されています。 その手段は、データタイプの説明をした後でないと説明が難しいので、その後 にします。 (2)の形式の 標準入力からファイル読み込みを行い、標準出力に出すプログ ラムは以下のようになります。 -----^ SAMP_01.ICN ( date:96-11-20 time:23:35 ) ------------<cut here procedure main() while line := read() do { # 1行読込みを繰り返す。失敗する迄。標準入力から。 write(line) # 出力。標準出力へ。 } end -----$ SAMP_01.ICN ( lines:5 words:15 ) --------------------<cut here while の考え方はほぼ、awkと同じです。 後に書かれた式 line := read() が【成功】している間は繰り返すという意味になります。 そしてその間は do以降を実行します。 (式という言い方は正確ではないかも。Icon教典では、expressionです。) read()はファイルからの読み込み関数(awkの関数相当)で、1行読み込みを 行い、【成功】時の関数の値は、読み込んだ行のデータです。 デフォルトでは標準入力から読み込みます。 (read()の括弧内にはファイルハンドルを指定できます。) := は代入です。 ここでは、変数lineにread()の値をセットしています。 (ちなみに = は数データの比較記号につかいます。 == は文字データの 比較記号です。) write()は出力関数です。(awkのprint相当) 出力ファイルはデフォルトでは 標準出力です。 lineの値を出力しています。 # は awkと同じくコメントの始まり記号です。 awkなら -----^ SAMP_02.AWK ( date:96-11-20 time:23:31 ) ------------<cut here { print } -----$ SAMP_02.AWK ( lines:3 words:3 ) ---------------------<cut here に相当します。 これを、Iconでは samp_01.icn のように表すわけです。 read()は、 awkの getline相当かな。 これだけでは、あまり面白くないので、Icon独自の補足を少し。 【ジェネレータ:generater】 read()はIconでは、ジェネレータと呼ばれるもの の1種です。 ジェネレータとは、値を次々に発生するもの のことです。データ発生器 とでもいいましょうか。 ファイルはふつう複数行からなりますので、read()は次々に行データを 発生することができますのでジェネレータの仲間ということになります。 【成功と失敗:success and failure】 Iconでは、【成功】と【失敗】という考え方があります。 あるプロセデュアがうまくいくと成功ということになり そのプロセデュアはある値を持ちます。 先のread()ではファイルからデータが読み込めている間は成功していて その結果、値(行データ)を持ちます。 すると read()を使っている式 line := read() も成功します。 その結果、値(この場合は同じく行データ)を持ちます。 その結果、while line := read() も成功します。 そこで、do以降が 実行されます。 do { ... } は失敗することもあります。 write(line)ができない時です。 例えば、ディスクエリアが無くなったときとかは、失敗します。 通常は、 ・ファイル末尾にきてデータが無くなり、read()が失敗し、 ・その結果 line := read() が失敗し、 ・その結果 while が失敗し、 while が終わります。 ついでに、 line := read() も値を持つと書きましたが、そのことからサンプル1は 次のようにも書けます。 -----^ SAMP_03.ICN ( date:96-11-20 time:01:40 ) ------------<cut here procedure main() while write(line := read()) end -----$ SAMP_03.ICN ( lines:3 words:7 ) ---------------------<cut here すると、一旦 lineにread()をセットする必要もありませんので -----^ SAMP_04.ICN ( date:96-11-20 time:01:41 ) ------------<cut here procedure main() while write(read()) end -----$ SAMP_04.ICN ( lines:3 words:5 ) ---------------------<cut here でも大丈夫です。 Iconでは、ジェネレータ、成功&失敗 が重要な概念です。 式そのものが値を持つという点は慣れると便利です。 それでは、第4回はこの辺で。 (なんとか続いているが、この項は何時終わるのだろうか?) 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 愛よりも激しく、誰よりも愛しく/Favorite Blue BGD: 大関のものも レンジでチン BGS: Mild Seven Menthol (icon_04.txt) ■ Icon > Icon入門講座(5) Iconの特徴は?(3) 風つかい 目次へ Iconを手入れたいと思ったのは、BYTEの94/5月号の The Icon Prgramming Language A new way to deal with strings and structure Ralph E Griswold という記事を読んでからでした。 awkよりいろんな機能が組み込まれているし、なかなか変わった言語だな〜。 ちょうどperlに挫折しかけていたので、これなら頭の切り替えができて勉強しやすい。 ということで、使いはじめました。(その代わりperlは完全に挫折しましたが。) 現在は、この記事はWWWでみることができます。urlは次の場所です。 http://www.byte.com/art/9405/sec12/art2.htm http://www.byte.comのサーバには、過去の記事の検索機能がありますので、 とにかくアクセスして、Icon programming で検索されても見つかると思います。 では、第5回をはじめます。 ひき続き awkとIconとの違いです。 4)パターンマッチの考え方 awkの場合は (1) awkが、読み込んだ行を、先頭から走査して、 (2) FSを探してFS以外の部分を順次 $1〜$nにセットします。 (3) 更に、 awkはスクリプトで指定した $1〜$n とパターンの照合指定に 従って照合し (4) アクションを決定します。 awkでは、(1)、(2)は自動的にやってくれる訳で、プログラマーは (3)以降を プログラムするのですが、 Iconの場合は (1)、(2)の部分からプログラムできます。 (逆にやらないといけない訳です。) そのせいか、正規表現を使った照合機能はIcon自体には組み込まれていません。 (ライブラリーにはありますので、必要なら使えます。) 次のデータ構造の話をしないと、Iconが、(1)、(2)のあたりのサポートのため にどんな機能を持っているか説明しづらいので、早々に次にいきます。 5)データ構造 awkは、データタイプとして、次のタイプがある(と思います)。 ・数 整数 実数 ・文字列 ・連想配列 −−−−−−−−−−−−これ以降はIconに比較してデータタイプといえる だろうというものです。 ・正規表現文字セット :[a-z]の様な文字の集合。 パターン指定にのみ使用可能。 Iconではcset ・正規表現文字列集合 :^#[0-9]+\/[0-9]+の様な文字列集合。 パターン指定にのみ使用可能 Iconにはありません。 ・ファイル ・関数 Iconでは次のデータタイプがあります。 ・null :awkでは不要。 ・数 整数 integer :awkと同じ 実数 real :awkと同じ ☆文字 cset :文字(の集合) ・文字列 strings :awkと同じ ☆集合 set :(何かの)集合 ☆リスト list :なんて説明しようか ・テーブル table :awkの連想配列相当 ・ファイル file ・procedure procedure :awkの関数相当 ☆(訳不明) co-expression :よくわかりません では、 私がわかるものを、おおまかに説明します。 ・null これは、 awkでは無いというより不要といった方が良いと思います。 awkでは、変数を使っても特に初期化をする必要はありません。 初期値は、0 か ""(空の文字列)のどちらかの適当な方に解釈され ます。 Iconでは、初期値はnullです。というか初期化されていない状態を nullというんでしょうね。 最初に代入されたときにタイプが(大抵 ・・・あんまし自信がありません。)決まります。 awkでは、たとえばカウンターを使う時、初期値 0は特に設定しなく てインクリメントしてもよいのですが、Iconでは、初期値をセットし ないと、nullに演算したといって怒られます。 ・数字は特に違いは無いと思います。 ・cset 文字の集合です。ここでいう文字とは、1バイトのキャラクターを意味 します。 これに相当するものは、 awkにもあります。 正規表現で、 [a-z]と書いたときには、アルファベットの小文字は全て適合するので アルファベットの小文字の集合と言えると思います。 それと同じもの です。 awkでは照合パターンの指定にしか使えませんが、Iconでは何時 でも使えます。 'abcdef1234' というような表記をします。これはアルファベットの aから fまでも文字 と 1から4までの数字の集合です。 よく使う文字セットには予め用意されています。 &ucase 英字大文字 A-Z &lcase 英字小文字 a-z &ascii ascci文字 &letter a-zとA-Z &digits 0-9 &cset 全文字(256個) でも何に使うんだろう? cset同士で演算ができます。 和 c1 ++ c2 差 c1 -- c2 積 c1 ** c2 ・string 文字列です。 これは awkと同じです。 "ABCDE" というように表します。 string同士の接続ができます。 接続 s1 || s2 部分文字列を切り出せます。 文字の位置指定にて行います。 位置は文字と文字の間を表しています。 ・先頭の文字の手前が 1で順に数えます。 ・末尾の文字の後ろは 0とも表示できます。 ・後ろからも指定できます。 マイナス側に数えます。 ・1文字だけ指定する場合は、後ろの指定は不要です。 s[n:n+1] は、s[n]という表記でかまいません。 例 "ABCDE"[1:3] は"AB" "ABCDE"[4:6] は"DE" "ABCDE"[4:0] は"DE" "ABCDE"[-2:0] は"DE" "ABCDE"[3:4] は"C" "ABCDE"[3] は"C" ・set 集合です。なにかの集まりを示します。要素は制限がありません。 csetでもstring でもlistでもsetでも。また混在しても構いません。 setは、空の setを生成して、要素を挿入するか 次に述べる listを setへ変換して生成するかで作成します。 ・list 順序つけされた、なにかの集まりです。これも要素は制限ありません。 csetでもstring でもlistでもsetでも。また混在しても構いません。 これは空のリストを定義して要素を追加するか、次の様に表記します。 ["ABCD",123,["abc"]] 文字列 "ABCD"と 数 123と "abc"を要素に持つリスト を要素に 持つリストの例です。 リストの要素は位置指定ができます。 ちょっと説明が面倒なので、 別変数に代入して説明します。 L := ["ABCD",123,["abc"]] L[1] は "ABCD" となります。 L[2] は 123 です。 L[3] は ["ABC"] です。 L[3][1] は "ABC" です。 L[1:3] は ["ABC",123] です。 リストには、先頭への要素の追加、先頭からの削除(兼取り出し) 末尾への要素の追加、末尾からの削除(兼取り出し) ができます。 ・table awkの連想配列と同じですが、生成指示が必要です。 T := table() とかで生成します。()には初期値が指定できます。(指定しないと nullが初期値) T["abcd"] := 123 と表記しますと、"abcd" をキーとして、データ 123をセットした ことになります。 ・file ファイルへの入出力の時に使うファイルハンドルです。 下記はキーワード指定できます。 &output ファイル出力のデフォルト指定なので 通常は指定不要。 write(line) は write(&output,line)を 意味します。 &input ファイル入力のデフォルト指定なので 通常は指定不要。 read() は read(&input)を意味する。 &errout 標準エラー出力指定。 write(&errout,line)の様に使います。 ・procedure なんでこれがタイプに分類されるのかよく理解していません。 ・co-expression これは全く理解できていません。 ふ〜。やっとデータ構造の所まできました。 あと制御構造をやったらパターン マッチングの説明ができるようになって、それでIconの特徴の説明はおしまいとなり ます。 ほんじゃ、第5回はここらで。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: MOSAIC/遊佐未森 BGD: かりん酒5:5お湯割り BGS: Mild Seven Menthol (icon_05.txt) ■ Icon > Icon入門講座(6)Iconの特徴(4)制御構造 風つかい 目次へ おっと〜。 またやってしまった。 前回のcsetの説明の中で、&ucase と &lcase の補足が逆です。 a-z とA-Z を逆に書いていました。 (追記 このテキストでは直っています。) では、第6回をはじめます。 しつこく awkとIconとの違いです。 6)プログラム制御構造 Icon は、制御構造として、次のものがあります。 ・順次処理 :順番にという当たり前の処理 ・if ... then ... else :awkとほぼ同じ。 ☆case :分岐、選択。 ☆every :全ての要素に対して、繰り返す。 ☆repeat :繰り返す。 ☆until :条件が成功するまで繰り返す。 ・while :awkとほぼ同じ。 ・& :両方が成功したら成功。 ・| :いずれかが成功したら成功。 ・関数 :awkの関数とほぼ同じ。組込みプロセデュア。 ・procedure :awkの関数とほぼ同じ。ユーザ関数。 ☆fail :強制的に失敗させる。 ・if ... then ... else は、次の様に使います if ss == "TOKYO" then write("東京") # == は文字列の照合記号 else write("不明") ssの場所にも、write("TOKYO")の場所にも、write("不明")の場所にも 式が使えます 上の例は次の様に書けます。 write(if ss == "TOKYO" then "東京" else "不明")) ・case は、次のように使います。 case ss of { "TOKYO" : write("東京") "YOKOHAMA" : write("横浜") default : write("不明") } ss という変数が、 "TOKYO" だったら、"東京"と出力し "YOKOHAMA" だったら、"横浜"と出力し それ以外だったら、 "不明"と出力します。 ssの場所にも、"TOKYO"の場所にも、write("東京")の場所にも式が使えます。 上の例は、if ... then ... else と同様に、 write( case ss of { "TOKYO" : "東京" "YOKOHAMA" : "横浜" default : "不明" } ) と書いても同じです。プログラム例を次にあげます。 -----^ SAMP_05.ICN ( date:96-11-22 time:23:19 ) ------------<cut here procedure main() # case の使用例 write(loc("TOKYO")) # procedure locを "TOKYO"を引数として呼ぶ。 write(loc("YOKOHAMA")) write(loc("CHIBA")) end procedure loc(ss) # ↑ssは仮パラメータ return case ss of { "TOKYO" : ("東京") "YOKOHAMA" : ("横浜") default : ("不明") } end -----$ SAMP_05.ICN ( lines:15 words:33 ) -------------------<cut here 実際のプログラムでは、こういう単純データ変換は、テーブル(awkの連想配列) を使うのが順当なやり方だと思いますが、そこはサンプルということで... ・everyは次のように使います。ジェネレータ(データを次々に発生するもの) に対し順に処理を行います。 -----^ SAMP_06.ICN ( date:96-11-23 time:20:33 ) ------------<cut here procedure main() # every の使用例 # サンプル用データ ss := "ABCD1234" # string LL := ["AB","CD",123] # list # ssの文字を1字づつ出力 every i := 1 to *ss do { # *は引き続くものの要素数を表わします。 write(ss[i]) # *ss はssの文字数を表わします。 } # LLの要素を1つずつ出力 every i := 1 to *LL do { # *LL はLLの要素数を表わします。 write(LL[i]) } # データを順に取り出す記号 ! を使うと簡潔に書けます。 # こちらが普通の記法 every write(!ss) # string の先頭から順に取り出し出力 # こちらが普通の記法 every write(!LL) # list の先頭から順に取り出し出力 end -----$ SAMP_06.ICN ( lines:21 words:68 ) -------------------<cut here ・repeat と until と while の使用例を次にあげます。 -----^ SAMP_07.ICN ( date:96-11-23 time:21:20 ) ------------<cut here procedure main() # repeat の使用例 # 1 〜10まで順に出力 count := 0 repeat { writes(" ",count +:= 1) # writes は、改行を出力しないwrite # n1 +:= n2 は n1 := n1 +n2 の省略記法 if count = 10 then break # break は、ループからの脱出 } write() # 改行出力 # until の使用例 # 1 〜10まで順に出力 count := 0 until count = 10 do writes(" ",count +:= 1) # count = 10が成功するまで # do 以降を繰り返す。 write() # while の使用例 # 1 〜10まで順に出力 count := 0 while count < 10 do writes(" ",count +:= 1) # count < 10が成功している間 # do 以降を繰り返す。 write() end -----$ SAMP_07.ICN ( lines:26 words:96 ) -------------------<cut here 尚、こういう簡単な条件だと、先ほどの every を使えば every i := 1 to 10 do write(" ",i) と書けます。 ・& は awkの && に相当します。 Iconでは、 & の左右に式が来ます。 awkでは条件式です。 awkでは条件式 (パターン指定) とそれ以外の式(アクション式)が区別されていますが Iconではその区別がありません。 式1 & 式2 は、式1を評価(実行)し、式1が成功したら、式2を評価 (実行する。)と言う処理になります。 例えば、以下の表記でも問題ありません。 write("AAA") & write("BBB") これは、 if write("AAA") then write("BBB") と同じです。 "AAA" と "BBB" を順に出力します。 ・| は awkの || に相当します。 Iconの場合は | の左右に式がきます。 左側の式が成功すると、右側の式は 実行されません。 左側の式が失敗すると右側の式が実行されます。 プログラム例を次に示します。コマンドライン引数(の1番目)をファイル 名としてファイルオープンし成功したら、ファイルを読み込んで行の頭に行 番号を付加します。 オープンできなかったら、エラーメッセージを出力し ます。 -----^ LINE_NO.ICN ( date:96-11-24 time:00:02 ) ------------<cut here procedure main(args) # add a line number to each line dir := open(args[1]) | stop("error") # コマンドライン引数にてファイル # オープン。失敗なら、"error"を # 出力しストップ。 line_no := 0 while line := read(dir) do write(line_no +:= 1,":",line) end -----$ LINE_NO.ICN ( lines:9 words:33 ) --------------------<cut here 別の言い方をしますと、 | は、ジェネレータを構成します。 式1 | 式2は、式1と式2を発生するジェネレータであり、 ・式1が成功すると成功し、式2の評価はしない。(実行しない。) ・式1が失敗すると、式2が評価される。 と言う処理になります。 every で、順次処理指定が前にきますと、まず式1が評価され次に、式2が 評価されます。 次の表記は、"AAA" と "BBB" を出力します。 every write("AAA" | "BBB") ・failは、処理を強制的に失敗させるのに使います。 でわ、では。第6回これくらいで。 さ〜て、やっと次回に文字列走査処理(string scannning)に移れます。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: HOPE/遊佐未森 BGD: ジャスミンティー BGS: Mild Seven Menthol (icon_06.txt) ■ Icon > Icon入門講座(7)Iconの特徴(5)スキャン 風つかい 目次へ 2〜3回で、Iconの特徴を述べる予定でしたが、もう7回目になってしまいました。 説明するって大変なんですね〜。 やっと今回の文字列走査(string scanning)で おしまいになる予定です。 これを早く説明したかったのですが、その前に説明して おかないといけないことが沢山あって... でも、これでも awkの知識をお持ちの 方を前提にしていますので、まだ楽なんで、 awkの知識が無い方をターゲットに説明 するのだともっと大変でしょう。 では、第7回をはじめます。 7)文字列走査(string scanning) まず、サンプルプログラムを。 スペースで区切られた文字列を順に出力する ものです。 -----^ SAMP_08.ICN ( date:96-11-24 time:18:12 ) ------------<cut here procedure main() # 文字列走査(string scanning )のサンプル # スペースで区切られた文字列を出力 # 対象文字列 line := " The Icon Programming Language" # line ? { # 走査対象文字列を指定:line # 走査位置は先頭から while tab(upto(cc := ~' ')) do # ' '以外の文字に出会ったら走査位置を # そこへ移動して、 do以降を実行 # ~cというのは、c以外の文字を表わす。 write(tab(many(cc))) # ' '以外の文字以外の文字(すなわち' ') # に出会ったら走査位置をそこへ移動して # 移動した走査位置の間の文字列を出力。 } end -----$ SAMP_08.ICN ( lines:18 words:50 ) -------------------<cut here 結果はこうなります。 -----^ SAMP_08.RST ( date:96-11-24 time:18:13 ) ------------<cut here The Icon Programming Language -----$ SAMP_08.RST ( lines:4 words:4 ) ---------------------<cut here 処理を順に説明していきます。 まず、 ? の記法ですが、これは走査対象文字列と 走査処理を示しています。 式1(走査対象文字列) ? 式2(走査処理) と表記します。 この表記を使ったときには、走査対象文字列指定は式1となります。 走査対象文字列にはキーワードが設けられています。 &subject です。 サンプルプログラムでは、 &subject := lineということになります。 Iconでは文字列の位置指定は文字と文字の間です。 位置指定が表しにくいので、 説明の便利のため、全角文字で対象文字列を示します。またスペースは■で表わしま す。 最初の文字T(実際は半角)の左が1の位置です。TheとIconの間のスペース の左側は5の位置となります。 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ■The■Icon■Programming■Language * 最初の &position (= 1) 走査は、文字列の先頭から始めます。すなわち最初の走査位置は、1となります。 この位置指定はキーワードが設けられています。 &position です。そこで最初は &position = 1 です。 while の後の式がまず実行されます。 upto(c,s)関数は、文字列 sを走査対象として、文字セット(c)の位置を探す関数で す。 sを省略した場合は、対象文字列は &subjectです。 文字が見つかった場合は成功して、uptoの値は、その探し出した文字の位置となり ます。 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ■The■Icon■Programming■Language * 最初の &position (= 1) * スペース以外を見つけたときの uptoの値 (=2) uptoは、最初にスペース以外の文字として先頭のスペースの後のTの検出に成功し てその値を 2とします。この時点では、&position は未だ、1のままです。 tab()は、&position を移動する関数です。 この場合は 2の位置へ移動します。 その時の tabの値は、前の位置と新たな位置との間の部分文字列と(すなわちスペ ース1個)となります。 (この値は使っていませんが。) 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ■The■Icon■Programming■Language * 最初の &position (= 1) * スペース以外を見つけたときの upto(cc)の値 (=2) * tab(upto(cc)) により &positionをここに移動。(=2) -- tab(upto(cc))の値は、移動した部分の文字列。(スペース) 次に、tab(upto(cc))が成功しましたので、do 以降が実行されます。 many(c,s)は、文字列 sを走査対象として、現在の &positionの位置以降の c以外の 文字を探します。 sが省略されていますと対象は &subject となります。 この場合は line の 2以降で、スペース以外の文字以外の文字(ややこしいですが、 すなわち スペース)を探します。 5の位置にスペースがありますので、manyは成功して、その値は、5となります。 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ■The■Icon■Programming■Language * &positionの位置(=2) * many(cc) の値(次のスペースの位置)(=5) tabの値は、前の値 2 と 今度の値 5 の間の文字列になります。 すなわち The となります。 この値を writeで出力している訳です。 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ■The■Icon■Programming■Language * 前の &positionの位置(=2) * many(cc) の値(次のスペースの位置)(=5) * tab(many(cc)) によりここに &positionを移動(=5) ------ tab(many(cc))の値は、移動した部分の文字列。(The) これで、do の処理が終わって、また while に戻ります。 どういう動きとなるかは、プログラムを以下のように書き換えて、&position の位置 を書き出して見ると分かりやすいかも。 -----^ SAMP_09.ICN ( date:96-11-24 time:18:39 ) ------------<cut here procedure main() line := " The Icon Programming Language" line ? while tab(write(upto(cc := ~' '))) do (tab(write(many(cc)))) end -----$ SAMP_09.ICN ( lines:4 words:19 ) --------------------<cut here 結果はこうなります。 -----^ SAMP_09.RST ( date:96-11-24 time:18:40 ) ------------<cut here 2 5 6 10 11 22 23 31 -----$ SAMP_09.RST ( lines:8 words:8 ) ---------------------<cut here 文字列走査支援関数のうち、upto,many,tab を説明しました。 この他に ・move(n) &position を nだけ動かす。 成功すると、動かした位置の間の文字列を 値とします。 ・any(c,s) 使ったことが無いのでよくわかりません。 ・bal(c1,c2,c3,s) これも使ったことが無いのでよくわかりません。 プログラム言語では、 開き括弧と閉じ括弧の数がふつう一致していないといけませんがそういう チェックに使えるみたいです。 で、awkでは自動的にやってくれる、カラム分解はどうやるかを次に例をあげます。 -----^ SAMP_10.ICN ( date:96-11-24 time:19:08 ) ------------<cut here procedure main(args) # 文字列走査(stirngs scanning)のサンプル # awk風のカラム分解の例 # ブロック1 ファイルオープン手続き Usage := "Usage : samp_10 input_file > output_file" # 使用法メッセージ # コマンドライン引数の数が1だったら、ファイルオープン。 if *args = 1 then dir := open(f_name := args[1]) | stop("cannot open ",f_name) # ファイルオープンできなければエラー表示 else stop(Usage) # 引数が1以外だったら使用法表示 write(&errout,f_name) # ファイル名表示 # ブロック2 ファイルを読み込みでスペース・タブで分割しリストに入れて、 # リストの要素を番号つきで出力 while line := read(dir) do { # ファイルからの1行読み込みを繰り返す。 L := split(line) # 読み込んだ行をスペース・タブで区切り # リストに変換する。 show_sln(L) # リストの要素を出力(実際のプログラム # ではここにいろんな処理を記述する。) } end # ブロック3 行をリストへ変換 procedure split(line,c) # 文字列を c(cset)で分割し、リストへ変換するプロセデュア /c := ' \t' # 引数に cが省略されていたら、スペースかタブとみなす # / はnullかどうかのチェック。nullならば...。 list := [] # 戻り値用リストを生成 line ? { # line を走査対象とする。 while tab(upto(~c)) do # c以外の文字が見つかったら走査位置をそこ迄移動 put(list,tab(many(~c))) # c以外の文字以外(すなわち c)が見つかる位置迄 } # 移動し、移動した位置の間の文字列をlistへ追加 return list end # ブロック4 結果表示procedure procedure show_sln(list) # リストの内容表示(テスト/表示用) every i := 1 to *list do writes(" ",i," :",list[i]) write() return end -----$ SAMP_10.ICN ( lines:43 words:132 ) ------------------<cut here う〜む。今回でスキャンを終わらせるつもりでいましたが、未だ終わりません。 あと、string で走査を行う関数が残っています。 それを次回に。 では、第7回はここらへんで。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 愛の言霊/サザンオールスターズ BGD: ジャスミンティー BGS: Mild Seven Menthol (icon_07.txt) ■ Icon > Icon入門講座(8)Iconの特徴(6)スキャン 風つかい 目次へ byte.com の記事検索は便利ですね。雑誌を購読していても古い雑誌の処分には悩み ます。 雑誌社の方でああいう仕掛けを持っていてくれると助かります。 国内の雑誌では無いですよね。 雑誌社と記事の著者との契約の問題だと思うのです が日本でもやってくれると、古い雑誌が捨てることができて助かるんですが。 さて、前回でIconの特徴を終わらせるつもりでしたが、stringでのスキャン処理が あふれてしまいましたので、続きです。 文字列から文字列を検索するための関数として、findと matchが用意されています。 ・match は、 awkの matchとほぼ同じです。(少し機能が多いのですが、私は同じ 使い方しかやっていないもので...) ・findは、uptoを string対応にしたものです。 find(s1,s2)は、文字列 s2を走査し、s1が見つかると成功しs1の開始位置を 値として持ちます。 簡単なサンプルを次に。 -----^ SAMP_11.ICN ( date:96-11-24 time:21:35 ) ------------<cut here procedure main() # find のサンプル # サンプルデータ # 確か中学の時、英語を勉強しはじめた時に、こんな例があったみたい。 line := "That that that that man used that place is wrong." # that の位置をかき出す。 map(line) ? while tab(write(find(s := "that"))) do move(*s) end # 補足 map(s1,s2,s3) は、文字変換関数です。s2:s3が変換テーブルになります。 # map("hello","el","EL") は、"hELLo"となります。 # s2,s3の指定がないときは、s2:&ucase,s3:&lcaseとなります。すなわち # 英文字はすべて小文字に変える関数となります。 -----$ SAMP_11.ICN ( lines:13 words:42 ) -------------------<cut here 結果はこうなります。 -----^ SAMP_11.RST ( date:96-11-24 time:21:35 ) ------------<cut here 1 6 11 16 30 -----$ SAMP_11.RST ( lines:5 words:5 ) ---------------------<cut here 日本語での照合を行う時は、コードが2バイトですので findで調べなければいませ ん。 Icon自体は英語の国の方が作りましたので、2バイト文字は意識していません。 2バイト文字も1バイトづつの処理になります。 で、何か使う上で困ることがあるかということですが、ほぼ、実際上の問題はありま せん。 データを扱う上では問題ないのですが、プログラム上に2バイト文字を表記する時に 若干の問題があります。2バイト目が、16進コードの 5C すなわち "\"になるコード の場合に、"\" がコンパイラにエスケープ文字と解釈されるためです。 その場合は、 その文字の後ろに "\"補ってやる必要があります。 例えば、MS漢字(シフトJIS)ですと write("表示") とすると、表の字が16進コードで 955Cとなりますので化け ます。 この場合、 write("表\示") とすると正常に表示されます。 こういうケースは、プログラムのテストの時点で文字化けが分かりますので、その 時点で手を加えれば良い訳です。 尚、データファイル中に 表 のような2バイト目が 5Cという文字があっても、 それをファイルから読み込んで string 操作して加工する分には、単なるデータ 扱いですので、問題は起きません。 というところで、Iconの特徴の項は終わりにします。 あと色んな関数があるのですが、説明はしきれません。 Icon の関数サマリーは、Icon教典には勿論載ってますが、下記にも含まれています ので、ご覧下さい。 ftp://ftp.cs.arizona.edu/icon/library/bipl.lzh このファイルは、グラフィック関係以外のライブラリー集です。 この中に、ihelp.icn と ihelp.dat というのが入っています。 このプログラムは Iconのヘルププログラムです。 ihelp.datには関数説明が載っています。 ところで、Iconには何に使えるのかよくわからない機能があります。 string に関数を代入できるのです。 -----^ NANJARO.ICN ( date:96-11-22 time:22:04 ) ------------<cut here procedure main() print := write # 関数 writeをprintに代入 print("AAA") # すると、printを writeと同様に使える。 end -----$ NANJARO.ICN ( lines:4 words:13 ) --------------------<cut here 関数名がstring だからできるとIcon教典(The Icon Programming Language)には 書いてあります。 ということは、これでも動くわけです。 -----^ NANJARO2.ICN ( date:96-11-23 time:11:27 ) -----------<cut here procedure main() "write"("AAA") end -----$ NANJARO2.ICN ( lines:3 words:4 ) --------------------<cut here 面白い機能だけれど、関数名を変えると紛らわしいような気がします。 やっと Iconの特徴の説明が終ったつもりでいますが、感じをわかっていただけた でしょうか? 次回からは、Iconプログラムの実例・・・といっても、私が使っているログ処理プロ グラムあたりを題材にすることになりますが。 では、第8回はここらへんで。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: LALALA Love Song/久保田利伸 BGD: ジャスミンティー BGS: Mild Seven Menthol (icon_08.txt) ■ Icon > Icon入門講座(9) データ構造 set 風つかい 目次へ 前回までで、Iconの特徴を awkと比較して説明したつもりだったのですが、読み返し てみると、データ構造のあたりで、使い方をだいぶ はしょってありますね〜。 set,list,tableについて補足をしようと思います。 というところで、第9回、いきま〜す。 set は、集合ですが、関連の関数の説明を。 ・set(L) 集合を生成するのは、set(L)関数を使います。 Lはリストです。 指定した リストの要素を持つ集合を生成します。 S := set() で空の集合ができます。 ということは、()に何も指定しない と、デフォルトでは、空のリスト[]が使われるということですね。 ・insert(S,x) 集合 Sに、要素 xを追加します。 xが既に Sに含まれるときは、Sは変化しま せん。 常に成功して、Sを値とします。 ・delete(S,x) 集合 Sから、要素 xを取り去ります。常に成功して、Sを値とします。 ・member(S,x) 集合 Sに、 xが含まれるかのチェックです。 成功すれば、xを値とします。 ・sort(S) 集合 Sをソートされた順に並んだリストに変換します。 ・演算 csetと同じように、和、差、積の演算ができます。 和 S1 ++ S2 差 S1 -- S2 積 S1 ** S2 set は、私は実用に使ったことがありませんので、良い例は出せないのですが、 Icon Newsletter に載っていた例に、若干手を入れたのがありますので、サンプルに。 【エラトステネスのふるい】というのを覚えておいでですか? 素数を洗い出す手続きですが、これをそのままプログラムして、ふるいをかける様子 を出力するプログラムです。 -----^ SIEVE.ICN ( date:96-11-26 time:00:32 ) --------------<cut here procedure main(args) ################################ # エラトステネスのふるいのデモ # ################################ # ふるいの大きさの設定 limit := args[1] | 100 # コマンドライン引数が無ければ、100。 # ふるいに入れる S := set() # every insert(S,1 to limit) # 始めますよ〜 write("エラトステネスのふるい") write("1 から ",limit," までふるいま〜す。") # ふるいの内容表示 disp(S) limit2 := integer(sqrt(limit)) # ルートNまでふるう。 # ふるいにかける every member(S,i := 2 to limit2) do { # せっせ、せっせ。 every delete(S,i + i to limit by i) write("\n","ふるいの目 : ",i," 残り : ",*S) disp(S) } # 終わったよ〜 write("\nふるいおわったよ!") end procedure disp(S) # セットをソートして、内容を出力。(表示/テスト用) L := sort(S) every writes(right(!L,4)) # right(s1,i,s2) 右寄せ桁合わせ関数、i:桁数 write("") # 余ったところには、s2を詰める。s2デフォルトは" " end -----$ SIEVE.ICN ( lines:34 words:90 ) ---------------------<cut here では、第9回はここらへんで。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 愛すること/辛島美登里 BGD: さつま白波5:5お湯割り BGS: Mild Seven Menthol (icon_09.txt) ■ Icon > Icon入門講座(10)データ構造 list 風つかい 目次へ 今回は、listです。 awkでは、連想配列に【感動】しましたが、Iconでは、このlist に【感動】しました。 なんせ便利なんですね〜。 しかし考えてみると、データ構造 が載っている本や雑誌には、必ずでてくるリスト構造が、 プログラム言語で標準的に サポートされていないなんて、とんでもないですよね〜。 市販の本に載っているよう なデータ構造とアルゴリズムは言語でサポートして欲しいな〜。 というところで、第10回、いきま〜す。 list は、 setや table(awkの連想配列)と異なり、要素の間に順番がついています ので、色んな取り扱いが必要です。 そこで支援関数も沢山あります。 ・list(x,i) リストを生成するには、いきなり L := ["AA","BB",12,34,["DD","EE"]] という風に書いてしまうか、このlist生成関数を使います。 この関数は、 xを i個分だけ要素に持つリストを生成します。 ただし私は使ったことがありません。 というのは、最初に空のリストを作っ て、そのリストに順次追加していく使い方をするもので、新規リスト生成は L := [] で間に合うためです。 ・リストへの追加・取り出し関数 put/get,push/pop,push/pull のペア関数があります。(pushはだぶって いますが。) 要素の順番が問題になりますので、次の3要素のリストにて説明します。 L := ["AA","BB","CC"] このリストは3要素のリストで、先頭が "AA"、次が "BB"、最後が "CC"と という構成です。 【個別アクセス】 このリストの要素へは、いきなり、L[1]、L[2]、L[3]と指定して アクセスできます。 (先頭) (末尾) ------ ------ ------ リスト L | "AA" | --- | "BB" | --- | "CC" | ------ ------ ------ ↑ ↑ ↑ 要素へのアクセス法: L[1] L[2] L[3] 【末尾へ追加し、先頭から取り出す】(QUE,FIFO方式) 追加要素は末尾の後ろへ追加し、取り去るときは先頭から取り去る場合は put/get のペア関数を使います。 ・put 末尾の要素の後ろへ要素を追加します。 put の値は、要素が追加されたリストなります。 ・get 先頭の要素をリストから取り出す(取り去り)ます。 get の値は、取り出した要素になります。 (先頭) (末尾) ------ ------ ------ リスト L | "AA" | --- | "BB" | --- | "CC" | ------ ------ ------ ↓ ↑ get 先頭から取り出し put 末尾へ追加 ------ ------ | "AA" | | "DD" | ------ ------ 【先頭へ追加し、先頭から取り出す】(Stack,LIFO方式) 追加要素は先頭の前へ追加し、取り去るときも同じく先頭から取り去る場合は push/pop のペア関数を使います。 ・push 先頭の要素の前へ要素を追加します。 push の値は、要素が追加されたリストなります。 ・pop 先頭の要素をリストから取り出す(取り去り)ます。 pop の値は、取り出した要素になります。 (pop は getと同じです。) (先頭) (末尾) ------ ------ ------ リスト L | "AA" | --- | "BB" | --- | "CC" | ------ ------ ------ ↑ ↓ push 先頭へ追加 pop 先頭から取り出し ------ ------ | "DD" | | "AA" | ------ ------ 【先頭へ追加し、末尾から取り出す】(QUE,FIFO方式) 追加要素は先頭の前へ追加し、取り去るときは末尾から取り去る場合は push/pull のペア関数を使います。 put/getと逆方向の使い方です。 ・push 先頭の要素の前へ要素を追加します。 push の値は、要素が追加されたリストなります。 ・pull 末尾の要素をリストから取り出す(取り去り)ます。 pull の値は、取り出した要素になります。 (先頭) (末尾) ------ ------ ------ リスト L | "AA" | --- | "BB" | --- | "CC" | ------ ------ ------ ↑ ↓ push 先頭へ追加 pull 末尾から取り出し ------ ------ | "DD" | | "CC" | ------ ------ ・sort(L) リスト Lからソートされた順に並んだリストを生成します。 ・sortf(L,i) リスト Lの i番目のフィールドにてソートしたリストを生成します。 あ、そうそう、基本的なことを忘れていました。リストは演算子で連結ができます。 L1 ||| L2 で、リストを連結できます。 また、部分リストは部分文字列と同じように指定できます。 L := ["AA","BB","CC"] として L[1:3] は、["AA","BB"] です。 L[2:0] は、["BB","CC"] です。 では、以上のサンプルプログラムを。 -----^ SAMP_12.ICN ( date:96-11-27 time:18:25 ) ------------<cut here procedure main() # リストの使い方のサンプル L := ["AA","BB","CC"] # サンプルデータ L2 := ["DD","EE"] write("リストの内容") write(" L := [\"AA\"\,\"BB\"\,\"CC\"]") write(" L2 := [\"DD\"\,\"EE\"]") write("個別位置指定サンプル") write(" L[1] : ",L[1]," L[2] : ",L[2]," L[3] : ",L[3]) L[2] := "XX" ; writes(" L[2] := \"XX\" L: ") ; show_sl(L) write("put/get サンプル") write(" put(L,\"FF\")") ; put(L,"FF") ; show_sl(L) writes(" get(L) : ") ; write(" ",get(L)) ; show_sl(L) write("push/pop サンプル") write(" push(L,\"GG\")") ; push(L,"GG") ; show_sl(L) writes(" pop(L) : ") ; write(" ",pop(L)) ; show_sl(L) write("push/pull サンプル") write(" push(L,\"HH\")") ; push(L,"HH") ; show_sl(L) writes(" pull(L) : ") ; write(" ",pull(L)) ; show_sl(L) write("sortサンプル") show_sl(sort(L)) write("リスト連結サンプル") writes(" L ||| L2 : ") ; show_sl(L ||| L2) write("部分リストサンプル") writes(" L[1:3] : ") ; show_sl(L[1:3]) writes(" L[2:0] : ") ; show_sl(L[2:0]) write("sortfサンプル") L3 := [["A1","B2","C3"],["A2","B3","C1"],["A3","B1","C2"]] write("原データ") ; show_wl(L3) write("フィールド1でソ\ート") ; show_wl(sortf(L3,1)) write("フィールド2でソ\ート") ; show_wl(sortf(L3,2)) write("フィールド3でソ\ート") ; show_wl(sortf(L3,3)) end procedure show_sl(list) # リストの内容表示(テスト/表示用) every writes(" ",!list) write() return end procedure show_wl(wlist) # 2重リストの内容表示(テスト/表示用) every list := !wlist do { every writes(" ",!list) write("") } write("") return end -----$ SAMP_12.ICN ( lines:61 words:166 ) ------------------<cut here では、第10回はここらへんで。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: The Incredible Jazz Guiter of Wes Montgomery BGD: 茉莉花茶 BGS: Mild Seven Menthol (icon_10.txt) ■ Icon > Icon入門講座(11)データ構造 table 風つかい 目次へ 今回は、table です。 table は、 awkの連想配列と同じものです。awkより若干、 支援関数が多くなっています。 さて、第11回を始めます。 では、table の支援関数の説明を。 ・table(value) table を生成するには、table()関数を使います。 T := table() で空の tableができます。 ()内には初期値を指定できます。 生成した後は、いきなり、 T["TOKYO"] := "東京" とか T["中山美穂"] := [1970,3,1,"O",158,80,60,84,45,"東京都小金井市"] とか key/value のペア形式でデータを挿入できます。 ・insert(T,key,value) table Tの、key に対する valueを追加します。keyが既に Tに含まれるとき は、keyに対する valueが更新されます。 Tを値とします。 ・delete(T,key) table Tから、key を取り去ります。 Tを値とします。 ・member(T,key) table Tに、keyが含まれるかのチェックです。成功すれば、keyを値とします。 ・key(T) table Tの keyを生成します。(ジェネレータ) ・sort(T,i) table Tをソートされた順に並んだリストに変換します。 i の値によって、リストの作り方とソートのやり方が違います。 i = 1 i = 2 [[key1,value1],[key2,value2],.....,[key_n,value_n]と連なったリスト keyでsort valueでsort i = 3 i = 4 [key1,value1,key2,value2,....,key_n,value_n]と連なったリスト keyでsort valueでsort では、サンプル、いきます。 -----^ SAMP_13.ICN ( date:96-11-28 time:02:30 ) ------------<cut here procedure main() # table の使い方のサンプル T1 := table() write("直接指定のサンプル") T1["TOKYO"] := "東京" T1["YOKOHMA"] := "横浜" T1["CHIBA"] := "千葉" show_st(T1) write("\nvalue がリストのサンプル") T2 := table() T2["中山美穂"] := [1970,3,1,"O",158,80,60,84,45,"東京都小金井市"] show_wt(T2) write("\ninsertのサンプル") insert(T1,"SAITAMA","埼玉") show_st(T1) write("\ndeleteのサンプル") delete(T1,"SAITAMA") show_st(T1) write("\nmemberのサンプル") if member(T1,s := "YOKOHAMA") then write(s," 有り") else write(s ," 無し") if member(T1,s := "SAITAMA") then write(s," 有り") else write(s ," 無し") write("\nsortのサンプル") T3 := table() T3["AA"] := "FF" T3["CC"] := "EE" T3["BB"] := "DD" write("オリジナルデータ") show_st(T3) write("\nkey sort ->[[key1,value1]...]") show_wl(sort(T3,1)) write("value sort ->[[key1,value1]...]") show_wl(sort(T3,2)) write("key sort ->[key1,value1,key2,value2...]") show_sl(sort(T3,3)) write("\nvalue sort ->[key1,value1,key2,value2...]") show_sl(sort(T3,4)) end procedure show_st(T) # table を key : value ペアで出力 every s_key := key(T) do write(s_key," ",T[s_key]) return end procedure show_wt(T) # valueがリストの table を key : value ペアで出力。 every writes(s_key := key(T)," :") do { every writes(" ",!T[s_key]) write() } return end procedure show_sl(list) # リストの内容表示(テスト/表示用) every writes(" ",!list) write() return end procedure show_wl(wlist) # 2重リストの内容表示(テスト/表示用) every list := !wlist do { every writes(" ",!list) write() } write() return end -----$ SAMP_13.ICN ( lines:80 words:159 ) ------------------<cut here では、第11回はここらへんで。 今後の予定は、 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: WINK/At Heel Diamond BGD: 大関のものも BGS: Mild Seven Menthol (icon_11.txt) ■ Icon > Icon入門講座(12)procedure/scope 風つかい 目次へ また、やってしまった。table(value)の説明で、T := set なんてやってしまって います。(追記 このテキストでは直っています。) setと同じ関数名が多いので、setの説明を修正して書いたんですが、修正がもれて しまいました。 さて、前回までは、データ構造の補足でしたが、 次は プログラム制御構造の補足です。 さて、第12回いきます。 今回は、procedure関係の補足です。 和訳すると手続きですが、awkの関数と同じ ものです。 いずれも、プログラムの構造化を支援するものです。 Iconでは組込み のものを関数(function)、ユーザが作ったものを手続き(procedure)と呼んでいます。 Iconではプログラムには、1つ(だけ)main() purocedureが必要です。 その中 には、ユーザ定義のprocedureを含むことができます。 そのユーザ定義のprocedure の中にもユーザ定義のprocedureを含むことができます。 --------------------------------------------- |procedure main() | | ........... | | aaa := nantara("AA","BB") | | ........... | | bbb := kantara("CC","DD","EE") | | ........... | | end | | | | --------------------------------- | | |procedure nantara(s1,s2) | | | | .......... | | | | return ... | | | |end | | | --------------------------------- | | --------------------------------- | | |procedure kantara(s1,s2,s3) | | | | .......... | | | | aaa := dotara("FF","GG") | | | | .......... | | | | return ... | | | |end | | | --------------------------------- | | | | --------------------------------- | | |procedure dotara(s1,s2) | | | | .......... | | | | return ... | | | |end | | | --------------------------------- | --------------------------------------------- 1)変数のスコープ 前の図の例で、aaaという変数を、mainの中でもkantaraの中でも使っていますが それぞれの有効範囲(scope)は各々のprocedureの中だけです。 scope はIconでは2種類設定できます。 local そのprocedureの中だけで有効。 特に指定しなければlocalと見なされます。 global 全procedureの中で有効。 2)procedure間のデータ受け渡し 前の図の例で、mainは、nantaraを使うときに、 nantara("AA",BB") という風に、2つのデータを渡しています。 nantara側で、このデータを使うときは、 procedure nantara(s1,s2) と書いておくと s1 := "AA" ; s2 := "BB" と解釈されます。 s1,s2という名前はどういう名前を使っても構いません。 引数の数が一定しない場合や多い場合はリスト渡しをします。 nantaraを使うときに、 nantara(List) という風に、リスト渡しをして、呼ばれる側で procedure nantara(args) として args[1]から順に使っていくというやり方です。 argsという名前は、どういう名前を使っても構いません。 nantaraは通常はmainに値を返さなければなりません。 return 式 という格好で返します。 式を書かなかった場合やnantaraが失敗した場合は nullが返ります。(というか、返らない場合はnullというのが正しいのかな) 3)もう1つの返し方 あるprocedureが呼んだprocedureに値を返すやり方には return 式 というやり 方の他に suspend 式 という返し方があります。 これは、式がジェネレータの場合に使います。 例えば、 suspend (1 | 2 | 3) と書くと、このprocedureは、呼ばれる度に順に 1、2、3の値を返します。 【済みません! 私は、このsuspendは使いこなせません。】 私はプログラムを構成するときには、そういう場合はすぐリストにして return [1,2,3] というような返し方にして、呼んだ側で順に処理するような処理をします。 じゃ〜、どういう場合に使うのかというと、Iconにはバック・トラッキング(ある 処理をやっていて、結果が失敗になると別の条件で試してみる)というプログラム の組み方をサポートしています。 そういう場合に役に立つ受け渡しのやり方らし いのですが... 前の例では、1というデータを呼んだ側が試してみてだめで失敗すると、2のデー タを試して、それもだめなら 3のデータで試す というような動きをサポートする ためらしいです。 (この項の話はあまり信用しないで下さい。) 4)main の引数 main の引数はコマンドライン引数がセットされます。コマンドライン入力の 引数は、次のように使います。 nantara AAA BBB CCC とした場合、nantara.icn にて procedure main(args) と書いておけば args[1] には、"AAA" args[2] には、"BBB" args[3] には、"CCC" がセットされます。 5)引数の省略 組み込み関数では、引数が省略できて、その時はデフォルト値が使われるものが あります。 引数が3個あるもので、2個しかセットされずにprocedureが呼ばれた場合には 呼ばれた側では、3番目の引数がセットされていないことになります。すなわち nullとなります。 そこで、実現方法としては、引き数がnullかどうかのチェックをすれば良い訳 です。 nullチェックは、第7回の split.icnの中で使っています、 /c := ' \t' の所です。 cがnullなら、' \t'をセットするという処理 となります。 尚、nullでなければ...というのは、\c := ... という表現になります。 5)1度だけよ! main 以外の procedure でも、最初に呼ばれた時だけ実行したい処理がでてくる 時があります。 初期設定処理です。 そういう処理は initial { ....... ....... } という書き方をすると、最初に呼ばれた時だけ実行するようにできます。 6)忘れたくない。 main 以外の procedureでは、initialで指定した以外の部分の処理は呼ばれる度 に実行されます。 前回呼ばれたときの事は忘れています。 しかし、でも、ある変数の値は保持しておきたい場合があります。 global指定をすれば可能ですが、構成が美しくありません。 そういう場合は static 指定をすれば、値は保持されます。 7)分割コンパイル 共通的に使うprocedureやデータは、ファイルとしても別にしておいて、それを 引用したいですよね。 Iconでは、2つのやり方があります。 ・$include "abcd.def" こういう指定をプログラム先頭にて行うと、"abcd.def"ファイルはその プログラムのソースファイルの一部として扱われます。 ・link common こういう指定をすると、common.icnは、そのプログラムの一部として 組込まれます。 commonを組み込むためには、common.icnを中間言語形式にコンパイルして おく必要があります。 icont -c common.icn という風にコンパイル指定を行うと、common.u1 common.u2 というファイル ができます。 これが中間言語形式のファイルです。 icon-projectにより、汎用的に使えそうな procedure や データを集めたものが ライブラリーとしてまとめられています。 ・bipl グラフィック以外のライブラリー ・gipl グラフィック関係のライブラリー(giplを引用している) urlは以下の通りです。 ftp://ftp.cs.arizona.edu/icon/library/bipl.lzh ftp://ftp.cs.arizona.edu/icon/library/gipl.lzh 各々1M強のファイルサイズです。 で〜。第12回はこの辺で。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: モモイズム/遊佐未森 BGD: 大関のものも BGS: Mild Seven Menthol (icon_12b.txt) ■ Icon > Icon入門講座(13)procedure/scopeサンプル 風つかい 目次へ 前回の procedure/scopeで書いた内容をサンプルプログラムで動作確認をしてなか ったので気になってやってみましたら、案の定、私が誤解していたころがありました。 削除して訂正版をアップしました。 2度読まれた方にお詫びします。 (追記 このテキストでは直っています。) さて、今回は前回の講座の補足として、サンプルプログラムをアップします。 -----^ SAMP_14.ICN ( date:96-11-30 time:00:52 ) ------------<cut here $include "samp_14b.icn" link disp procedure main(args) # procedure の使い方のサンプル # コマンドライン引数のテスト # samp_14 abc def 123 と起動すると、abc、def、123を出力する。 write("コマンドライン引数は以下の ",*args," 個です。") every write(!args) # $includeで定義したprocedure test_05() # procedure間のデータの渡し方 write("リスト渡し:") data1 := ["AA","BB"] show_sl(data1) test_01(data1) write("個別渡し:") write(s1 := "CC"," ",s2 := "DD") test_02(s1,s2) write("戻り値:") show_sl(test_03()) # suspendのテスト write("suspend のサンプル") every write(!test_04()) write("back tracking の非常に簡単なサンプル") write("test_04() の値が 3 以外は失敗させた時の動きの例") write("同じ数字が2個続けば成功しています。") write(write(test_04()) = 3) end procedure test_01(args) write("リスト受け:") show_sl(args) return end procedure test_02(s1,s2) write("個別受け:") write(s1," ",s2) return end procedure test_03() return ["EE","FF"] end procedure test_04() suspend 1 | 2 | 3 end -----$ SAMP_14.ICN ( lines:54 words:88 ) -------------------<cut here $include で引用するファイルです。 -----^ SAMP_14B.ICN ( date:96-11-30 time:00:53 ) -----------<cut here procedure test_05() write("$include test") end -----$ SAMP_14B.ICN ( lines:3 words:5 ) --------------------<cut here 第11回の samp_13.icn の表示プログラムの部分を別ファイルにしたもの。 icont samp_14.icn を行う前に、icont -c disp.icn で中間言語に変換して おきます。 -----^ DISP.ICN ( date:96-11-29 time:23:12 ) ---------------<cut here procedure show_st(T) # table を key : value ペアで出力 every s_key := key(T) do write(s_key," ",T[s_key]) return end procedure show_wt(T) # valueがリストの table を key : value ペアで出力。 every writes(s_key := key(T)," :") do { every writes(" ",!T[s_key]) write() } return end procedure show_sl(list) # リストの内容表示(テスト/表示用) every writes(" ",!list) write() return end procedure show_wl(wlist) # 2重リストの内容表示(テスト/表示用) every list := !wlist do { every writes(" ",!list) write() } write() return end -----$ DISP.ICN ( lines:31 words:70 ) ----------------------<cut here ほんじゃ。第13回はこの辺で。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 愛が止まらない/WINK BGD: 玄米茶 BGS: Mild Seven Menthol (icon_13.txt) ■ Icon > Icon入門講座(14)type変換、他 風つかい 目次へ Iconの特徴の項で、やり残した説明を補足してきました。一応、今回でそれも終わる 予定です。 さて、今回はデータのtype変換あたりを補足説明したいと思います。 では、第14回、いきま〜す。 1)type変換 Iconでは、データ構造のところで説明しましたような色んなデータタイプがあり ます。 このデータタイプは、自動変換される場合と、意識的に変換してやらない といけない場合があります。 ・nullには、どんなデータタイプも代入できます。 変数は初期値は nullですが、そこには、数字でも stringでもでもlistでも 代入できます。 ある procedureの中で初めて使うのであれば、 いきなり no := 0 name := "辛島美登里" WINK := ["相田翔子","鈴木早智子"] とかできるわけです。 ・違うtype同士のデータの演算はできません。 上の例に引き続き xxx := no + name とか WINK +:= 1 (WINK := WINK +1 の略記) をしようとすると、実行時エラーになります。 また、いきなり、typeの決まっていない変数を使って演算しようとすると やはりエラーになります。 数字のrealとintegerは演算できます。これはできないとね。 ・組み込み関数の引数では、できる範囲は自動変換されます。 write(no) とやると、数字の 0は、文字 "0"へ変換されます。 cset,integer,real,string間ではできる範囲はやってくれるみたいです。 私は、エラーがでたら、きちんと変換するといういい加減なやり方をして います。ハイ。 以下に type変換関数をあげます。 これもできる範囲しかできないわけですが。 ・string(x) 文字列へ変換 ・numeric(x) 10進数へ変換(10進数表記文字列のみ) ・cset(x) 文字セットへ変換(文字とは1バイトキャラクタ) ・integer(x) 10進整数へ変換(10進数表記文字列のみ) Iconでは、ある変数がどういうtypeかチェックする関数があります。その名は ずばり、 type(x)です。 これを使うと、引数のデータタイプによって処理を 分ける procedureが作れます。 2)照合 Iconではデータの照合記号がデータによって異なります。 等号 不等号 比較 比較 比較 比較 数字では、 = ~= < <= > >= 文字(列)では、 == ~== << <<= >> >>= 一般的な値比較は、=== ~=== です。 すみません。 ===の使い方はよく理解していません。 尚、照合式も値を持ちます。 式1 照合記号 式2 が成功しますと、式2の値を もちます。 例えば、 20 > nn は成功すれば、nnの値を持ちます。 比較記号と 代入記号:= をつなぐと比較結果を、代入できます。 例えば、 nn >:= 5 は、成功すると、nnに 5が代入されます。 3)文字発生/文字番号 Iconでいう文字は、1バイトで表せるものということで、256通りの文字が ありえます。256文字全体を含んだ文字セットとして、&csetというキーワード があります。(&csetは、どう使うのかわかりません。) で、16進コードの 00からFFまでの256文字には、0〜255まで番号が つけられていて、この番号指定で文字を指定できます。 ・char(n) n番目の文字を生成します。 ・ord(c) 文字 cの番号を生成します。 4)文字列整形 以下の関数により文字列の整形ができます。 ・right(s1,i,s2) s1を i桁に右寄せで整形する。余りには、s2が詰められる。 ・left(s1,i,s2) rightの左寄せ版 ・center(s1,i,s2) i文字列として、真ん中寄せ。余りには、s2を使う。 s2のデフォルトはスペース。 ・trim(s,c) 末尾の文字(c)を取り去る。(末尾のスペースを取り去るのによく使う) cのデフォルトは、スペース。 ・entab(s)/detab(s) スペースをタブコードにしたり、タブコードをスペースへ変換します。 5)文字変換 map(s1,s2,s3) s1の中の文字を、s2:s3の変換テーブルで、変換します。 s2,s3のデフォルト は、&ucase(英字大文字)、&lcase(英字小文字)です。よってs2,s3を省略す ると、英字大文字を小文字へ変換する関数になります。 それでは、今回のサンプルプログラム、いきます。尚、dispは前回と同じものです。 -----^ SAMP_15.ICN ( date:96-12-01 time:00:03 ) ------------<cut here link disp procedure main() write("★type変換サンプル") write("★nullへのセット") write(no := 0) write("My favorite singer :",name := "辛島美登里") writes("WINK :") show_sl(WINK := ["相田翔子","鈴木早智子"]) write("★type不一致エラーのサンプル:コメントアウトされています。") # xx := no + name # エラーがでるのでコメントアウト # WINK +:= 1 # エラーがでるのでコメントアウト # yy +:= 1 # エラーがでるのでコメントアウト write("★type変換関数の例 ・・・最終的には stringに変換されています。") write("string(128) :",string(128)) write("numeric(\"128\") :",numeric("128")) write("cset(128) :",cset(128)) write("integer(\"128.5\") :",integer("128.5")) write("real(\"128.5\") :",real("128.5")) write("★関数typeの使用サンプル") write("noのタイプは :",type(no)) write("nameのタイプは :",type(name)) write("WINKのタイプは :",type(WINK)) write("WINK[1]のタイプは :",type(WINK[1])) write("T := table() のタイプは :",type(T := table())) write("S := set() のタイプは :",type(S := set())) write("cc := \'abcd1234\' のタイプは :",type(cc := 'abcd1234')) write("128.5 のタイプは :",type(128.5)) write("show_sl のタイプは :",type(show_sl)) write("★比較記号の使用サンプル") write("nn := ",nn := 10) write("20 > nn の値 :",20 > nn) write("nn >:= 5 での nnの値 :",nn >:= 5) write("★char/ordの使用サンプル") write("ord(\"A\") :",ord("A")) write("char(ord(\"A\")) :",char(ord("A"))) write("★文字列整形関数の使用サンプル") write("right(\"ABCD\"\,10\,\"xyz\") :",right("ABCD",10,"xyz")) write("left(\"ABCD\"\,10\,\"xyz\") :",left("ABCD",10,"xyz")) write("center(\"ABCD\"\,10\,\"xyz\") :",center("ABCD",10,"xyz")) write("trim(\"aaabbbxxxdddxxx\"\,\'x\') :",trim("aaabbbxxxdddxxx",'x')) write("★entab/detabの使用サンプル") write("detab(\"abc\\tdef\\tfgh\") :",detab("abc\tdef\tfgh")) write("entab(\"abc def fgh\") :",entab("abc def fgh")) write("★mapの使用サンプル") write("map(\"ABCDEF\"\,\"ABC\"\,\"123\") :",map("ABCDEF","ABC","123")) write("★mapの使用サンプル/データ入れ替え") write("map(\"54321\"\,\"12345\"\,\"ABCDE\") :",map("54321","12345","ABCDE")) end -----$ SAMP_15.ICN ( lines:56 words:141 ) ------------------<cut here では、第14回はこの辺で。少し説明残りがでましたので、それは次回に。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 空耳の丘/遊佐未森 BGD: 茉莉花茶 BGS: Mild Seven Menthol (icon_14.txt) ■ Icon > Icon入門講座(15)エスケープ文字、他 風つかい 目次へ 前回、少し説明残りがでましたので、補足をします。 では、15回、いきます。 1)エスケープ文字 エスケープ文字は次の通りです。 \b backspace \v vertical tab \d delete(rubout) \' single quote \e escape (altmode) \" double quote \f formfeed \\ backslash \l linefeed (newline) \ddd octal code \n newline (linefeed) \xdd hexadecimal code \r carriage return \^c control code \t horizontal tab 2)キーワード 私には、どう使うのか分からないのもありますが、次の通りです。 &allocated : i1,i2,i3,i4 # accumulated bytes allocated # (total,static,string,block) &ascii : c # cset of ascii characters &clock : s # current time of day &collections : i1,i2,i3,i4 # collection count # (total,static,string,block) &cset : c # cset of all characters ¤t : C # current co-expression &date : s # current date &dateline : s # current date and time &digits : c # cset of digits 0-9 &dump : i # if non-zero, causes dump on termination &e : r # base of natural logarithms, 2.71828... &error : i # run-time error conversion control &errornumber : i # run-time error number &errortext : s # run-time error message text &errorvalue : x # run-time error offending value &errout : f # standard error output file &fail # fails &features : s1,s2,...,sn # implementation features &file : s # current source code file name &host : s # string identifying host computer &input : f # standard input file &lcase : c # cset of lower case letters a-z &letters : c # cset of all letters A-Za-z &level : i # level of current procedure call &line : i # current source code line number &main : C # main co-expression &null : n # the null value &output : f # standard output file &phi : r # The golden ratio, 1.61803... &pi : r # The value of pi, 3.14159... &pos : i # string scanning position &progname : s # file name of the executing program &random : i # random number seed ®ions : i1,i2,i3 # current region size # (static,string,block) &source : C # activator of current co-expression &storage : i1,i2,i3 # current bytes allocated # (static,string,block) &subject : s # string scanning subject &time : i # current run time in milliseconds &trace : i # procedure tracing control &ucase : c # cset of upper case letters A-Z &version : s # version of Icon 3)算術・論理関数 私はあんまり使う機会がありませんが、次のとおりです。 abs(N) : N # compute absolute value acos(r1) : r2 # compute arc cosine asin (r1) : r2 # compute arc sine atan (r1,r2) : r3 # compute arc tangent cos(r1) : r2 # compute cosine dtor(r1) : r2 # convert degrees to radians iand(i1,i2) : i3 # compute bit-wise and icom(i1) : i2 # compute bit-wise complement integer(x) : i # convert to integer(切上げ関数に使える) ior(i1,i2) : i3 # compute bit-wise inclusive or ishift(i1,i2) : i3 # shift bits ixor(i1,i2) : i3 # compute bit-wise exclusive or log(r1,r2) : r3 # compute logarithm rtod(r1) : r2 # convert radians to degrees sin(r1) : r2 # compute sine sqrt(r1) : r2 # compute square root tan(r1) : r2 # compute tangent 今回で、私の分かる範囲は、説明を終わりました。 次回は、私が使っているプログラム例を説明したいと思います。 それでは、第15回はこの辺で。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 咲き誇れ愛しさよ/WINK BGD: 茉莉花茶 BGS: Mild Seven Menthol (icon_15.txt) ■ Icon > Icon入門講座(16)wild.icn 風つかい 目次へ 前回、タイトルが間違っていましたね〜。(追記 このテキストは直っています。) それと前々回に、文字列操作関数を2つ忘れていました。では、16回、いきます。 まず、忘れた文字列操作関数を ・reverse(s1) 文字列の向きを入れ替えます。 "ABCD" を、"DCBA"へ変換する関数です。 ・repl(s1,i) 文字列 s1を i個分つなぐものです。 では、本題の wild.icnの話しへ戻ります。 予定では、YAX形式のバインダーの iyab.icnを説明する予定だったのですが、そこから呼んでいる wild.icnを先にやんな くちゃ。 ということで、wild.icnの説明を先に。 Iconは、ファイル読み込みをプログラムに記述して行います。 そこで、ワイルド カード指定でファイルを複数まとめて処理する時には、そのための procedureを作ら ないといけません。 wild.icnは、 ・引数のファイル指定に従って、MS-DOSへ"DIR"コマンドを発行し、その結果を テンポラリーファイルへ出力します。 例えば、"dir *.icn >> $$$tmp.$$$" です。 ・Iconは、このテンポラリーファイルを読み込んで解析して、ファイル毎の ・フルパス付きファイル名 ・ファイルサイズ ・日付 ・時刻 を要素として持つリストのリストを値として持ちます。 ・該当ファイルが無い場合は失敗します。 ・先頭に @をつけたファイル名リストによるファイル指定にも対応しています。 尚、"dir"コマンドの結果は メーカー・バージョンによって異なりますので、お使い の機種によっては修正が必要かも知れません。 -----^ WILD2.ICN ( date:96-12-01 time:19:52 ) --------------<cut here link dir2lst2 procedure wild(args) # wild.icn Ver.1.1 1996/10/26 windy Ver.1.3 1996/12/01 windy # Usage: wild(file(s) or @file_list) # : sortf(wild(file(s) or @file_list),1) ファイル名でsortする場合 ################### # ファイル指定コマンド行処理 ################### # ワイルドカードファイル指定のファイルの情報を"dir" を発行して調べてリスト # にして返す。 # レスポンスファイルも指定可。(@file_list) # value : [i][1] フルパス付きファイル名、[i][2] ファイルサイズ、[i][3] 日付 # : [i][4] 時刻 i : 1 〜 ファイルの数 # 該当ファイルが無ければ失敗(fail) tmp := "$$$tmp.$$$" # テンポラリファイル名設定 if s := getenv("TMP") then tmp := s || "\\" || tmp # 環境変数にテンポラリ # ディレクトリが設定してあれば # ファイル名の前に追加 fn_list := [] # ファイル名等格納リスト # コマンドラインのファイル指定をもとに、"dir" コマンドを発行し、tmpへぶち込む。 if *args = 0 then fail # ファイル指定なし else { every arg := !args do { # コマンドライン引数リストから順に取り出し。 case arg[1] of { # caseを使ってみたかったのだ。 "@" : { # response file指定 dir := open(arg[2:0]) | stop("cannot open " || arg[2:0]) while line := read(dir) do { if not upto('.',line) then line ||= "." # 拡張子が無 system("dir " || line || " >>" || tmp) # い時には"." } # を追加 close(dir) } default : { if not upto('.',arg) then arg ||= "." system("dir " || arg || " >>" || tmp) # ファイル指定 } } # end of case } # end of every } # end of else dir := open(tmp) | stop("cannot open " || tmp) # ファイルオープン # "dir" の結果格納ファイルから、ファイル指定部分を抜き出してリストへぶち込む。 while line := read(dir) do # tmpファイルから1行づつ読込。 put(fn_list,dir2lst(line)) # ファイル情報を抜き出して、 # リストへ格納 close(dir) remove(tmp) # 証拠隠滅 #################### # コマンド解析終了 #################### if *fn_list = 0 then fail # 該当ファイル無し else return fn_list end -----$ WILD2.ICN ( lines:56 words:236 ) --------------------<cut here -----^ DIR2LST2.ICN ( date:96-12-01 time:20:16 ) -----------<cut here link split2, strings2 #################### # dir2lst.icn Ver.1.1 1996/11/3 Ver.1.2 1996/12/1 windy # Usage : dir2lst(line) # "dir" コマンドの結果を1行ずつもらい、ファイル部分ならファイル属性をリストに # して返す。 ファイル部分で無ければ失敗(fail) # value : [1] フルパス付きファイル名、[2] ファイルサイズ、[3] 日付、: [4] 時刻 ################### procedure dir2lst(line) static c_dir # ディレクトリー指定 line ? { if find(" ディレクトリ") then { if (c_dir := split(line)[-1])[-1] ~== "\\" then c_dir ||:= "\\" # ↑ディレクトリー名末尾に"\\"がついていなければ追加。 fail } if {*line = 0} | {line[1] == " "} then fail # not file if find("<DIR>") then fail # not file if find("あります") then {c_dir := "" ; fail} # c_dir リセット } # end of line ? list := split(line) # カラム分割 # case *list of { 3 : put(list,"00:00") # PC-98 no_EXT and 00:00 # ↑00:00は出ないので補う。 4 : { if charcnt(list[4],&digits ++ '-') = 8 # date test # ↑数字とハイフンだけかとういうチェック then { put(list,"00:00") # PC-98 00:00 push(list,pop(list) || "." || pop(list)) # ↑ファイル名と拡張子を取り出して、"."でつなぐ。 } else { if charcnt(s := list[4],&digits ++ ':') ~= *s # time test then list[4] := "00:00" # PC-98 00:00 } } default : { if charcnt(list[4],&digits ++ '-') = 8 # date test then { if charcnt(s := list[5],&digits ++ ':') ~= *s # time test then list[5] := "00:00" # PC-98 00:00 push(list,pop(list) || "." || pop(list)) } else { if charcnt(s := list[4],&digits ++ ':') ~= *s # time test then list[4] := "00:00" # PC-98 00:00 } } } list[1] := c_dir || list[1] # ディレクトリーを補う。 list[2] := deletec(list[2],',') # "\,"を取り去る。 list[4] := right(list[4],5,"0") # 時刻の10時の桁を補う。 return list[1:5] end -----$ DIR2LST2.ICN ( lines:54 words:248 ) -----------------<cut here -----^ SPLIT2.ICN ( date:96-12-01 time:19:53 ) -------------<cut here # 文字列を指定文字(セット)で区切りリストに入れる。 procedure split(line,c) # function : split a strings with c and store a list(exclude c) /c := ' \t' # 指定が無ければスペースかタブとみなす。 list := [] # return用リスト生成 line ? while tab(upto(~c)) do put(list,tab(many(~c))) return list end -----$ SPLIT2.ICN ( lines:8 words:37 ) ---------------------<cut here -----^ STRINGS2.ICN ( date:96-12-01 time:19:51 ) -----------<cut here ############################################################################ # biplの中のstrings.icnから、講座で使うものだけ取り出したものです。 ############################################################################ # charcnt(s, c) 文字列内の特定文字(セット)数をカウント。 # deletec(s, c) 文字列から特定文字(セット)を取り去る。 ############################################################################ procedure charcnt(s, c) #: character count local count count := 0 s ? while tab(upto(c)) do count +:= *tab(many(c)) return count end procedure deletec(s, c) #: delete characters local result result := "" s ? { while result ||:= tab(upto(c)) do tab(many(c)) return result ||:= tab(0) } end -----$ STRINGS2.ICN ( lines:21 words:61 ) ------------------<cut here それでは、第16回はこの辺で。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: なし。 BGD: 茉莉花茶 BGS: Mild Seven Menthol (icon_16.txt) ■ Icon > Icon入門講座(17)Test Driver for wild 風つかい 目次へ 前回、wild.icn とその中で使っている procedureだけを示しましたが、実際はテス ト用のドライバーやテストデータを作ってテストしています。 それがないと、動きがわかりにくいと思いますので、その部分を参考にアップロード します。 では、17回、いきます。 dir2lst のテストドライバーです。 "DIR"コマンドの結果ファイルを読み込んで dir2lstで処理した結果を書き出すものです。 -----^ DIR2LST~.ICN ( date:96-12-01 time:19:19 ) -----------<cut here link dir2lst2, disp # a test driver and a stub for dir2lst.icn # Usage: dir2lst~ >dir2lst.rst procedure main() write("test for dir2lst.icn\n") dat := open(s := "dir2lst.dat") | stop("cannot open ",s) while line := read(dat) do { write(line) writes("->") show_sl(dir2lst(line)) } end -----$ DIR2LST~.ICN ( lines:12 words:41 ) ------------------<cut here "DIR"コマンドの結果ファイルです。 お使いのマシンの結果でテストして みて下さい。 -----^ DIR2LST.DAT ( date:96-11-27 time:02:24 ) ------------<cut here IBM Aptiva530 Win95のDOS窓 PC-DOS J6.1 ドライブ D: のボリュームラベルはありません. ボリュームシリアル番号は 2727-1AF8 ディレクトリは D:\ICN . <DIR> 96-10-26 20:06 . .. <DIR> 96-10-26 20:06 .. AAA AAA 10 96-10-26 20:06 AAA.AAA BBB BBB 10 96-10-26 20:07 BBB.BBB CCC 6 96-10-26 20:07 CCC CCC 6 96-10-26 CCC ↑テスト用に付加したデータ(実際にはこんなデータは無い) SRC <DIR> 96-10-26 20:07 SRC 3 個 26 バイトのファイルがあります 3 ディレクトリ 44,810,240 バイトの空きがあります PC-9801VM21 MS-DOS 3.3D のDOSプロンプト ドライブ B: のディスクのボリュームラベルは user ディレクトリは B:\ICN CCC 729 95-06-16 AAA AAA 729 95-06-16 BBB AAA 1077 95-06-08 14:47 3 個のファイルがあります. 3682304 バイトが使用可能です. ドライブ I: のディスクのボリュームラベルは RAMDISK1920 ディレクトリは I:\ RCS <DIR> 95-06-23 0:50 AAA AAA 729 95-06-16 BBB AAA 1077 95-06-08 14:47 CCC 1077 95-06-08 14:47 4 個のファイルがあります. 1949696 バイトが使用可能です. IBM Aptiva530 Win3.1 DOS窓 PC-DOS J6.3 ドライブ C にはボリューム・ラベルがありません ボリューム・シリアル番号は 255B-1DDB です ディレクトリーは C:\ICON\MY_PROGS . <DIR> 96-05-04 18:03 .. <DIR> 96-05-04 18:03 MAX_LEN ICN 326 96-02-06 1:01 PAGE ICN 2,975 96-02-06 1:15 DISP_COL ICN 553 96-05-05 18:26 TRIM ICN 68 95-06-26 14:29 ADD_NO ICN 267 96-05-07 22:50 ICON2U ICN 704 96-05-12 2:09 IYABP ICN 2,563 96-05-04 16:19 IYABPL ICN 2,520 96-05-04 16:17 ICON2E ICN 701 96-05-12 2:08 TEST ICN 41 96-05-07 23:00 12 個 10,718 バイトのファイルがあります 81,821,696 バイトが使用可能です -----$ DIR2LST.DAT ( lines:57 words:188 ) ------------------<cut here wildのテストドライバーです。 想定したパターンのテストデータを与えて 結果を書き出します。 -----^ WILD2~.ICN ( date:96-12-01 time:20:30 ) -------------<cut here # a test driver and stub for wild.icn # Usage: wild2~ > wild.rst link wild2, disp procedure main() write("test for wilds.icn\n") write((L := ["abc"])[1]) show_wl(wild(L)) | write(L[1],"は見つからない。\n") write((L := ["*.*"])[1]) show_wl(wild(L)) write((L := ["*.icn"])[1]) show_wl(wild(L)) write((L := ["wi*.*"])[1]) show_wl(wild(L)) write((L := ["@WILD_FL.DAT"])[1]) show_wl(wild(L)) every writes(" ",!(L := ["*.icn","*.dat"])) ; write() show_wl(wild(L)) end -----$ WILD2~.ICN ( lines:25 words:52 ) --------------------<cut here wild~で使うレスポンスファイルです。 -----^ WILD_FL.DAT ( date:96-12-01 time:19:38 ) ------------<cut here wild_fl.dat wild2~.icn -----$ WILD_FL.DAT ( lines:2 words:2 ) ---------------------<cut here それでは、第17回はこの辺で。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: なし。 BGD: 大関のものも BGS: Mild Seven Menthol (icon_17.txt) ■ Icon > Icon入門講座(18)iyab.icn 風つかい 目次へ 今回でやっと YAX形式のファイルバインダー iyab.icnの説明にたどり着きました。 では、18回、いきます。 YAX形式というのは、次のようなプログラムの前と後ろに識別行を付加した アップロード用プログラム形式のことです。 -----^ SAMP_16.ICN ( date:96-12-01 time:21:59 ) ------------<cut here procedure main() write("sample") end -----$ SAMP_16.ICN ( lines:3 words:4 ) ---------------------<cut here この形式は、日経mixのawk会議で、当時議長だったtakun(AWK教典:The AWK Programming Language の訳者です。)達がまとめられた形式です。 awkのプログラム(スクリプト)は短いのが多いので、通常の書き込みの中に 書き込んでも問題ないのですが、紛れてしまうので、前後にはじめと終わりの 行をつけようということで、議論があったような気がします。 だいぶ古い話し ですので、もうよくは覚えていません。 awkのプログラムとしては、上記形式にする yab.bat と、ログファイルから スクリプトを抜き出す yax.bat があるのですが、ここで取り上げるのは、 yab.bat (yet another binder)の方です。 では、iyab.icn のプログラムを次に。 wild.icn関係のプログラムを引用し ています。 -----^ IYAB2.ICN ( date:96-12-01 time:22:44 ) --------------<cut here link wild2,top2,split2 procedure main(args) # iyab2.icn 1.1 1995/06/23 windy 1.10 1996/12/01 windy Usage := "Usage : iyab2 input_file(@file_list) >output_file" ################### # YAX.LZH awkスクリプト掲載標準形式布教パッケージ Version 1.00 July/4/1990 # by takun@日経MIX のYAB.BATをIconに置換したもの。細かい動作は多少異なる。 ################## if *args = 0 then stop(Usage) # ファイル指定無し。 else fn_list := wild(args) | stop(Usage) # コマンド行解析 # argument : コマンドラインからのファイルリスト。 # レスポンスファイル指定可(@file_list) # value : リスト [i][1] フルパス付きファイル名、[i][2] ファイルサイズ # [i][3] 日付、[i][4] 時刻、i : 1〜ファイルの数 # ファイルサイズは使用せず。 #################### # バンドル処理設定 #################### head := "-----^ " trail := "-----$ " # please change the next line as you like it. # (お気に召すまま変えてちょうだい。) width := 60 # 切取り線の長さ; コメントが要らないときは 0 # select or change as you like it. (あなた好みに変えていいのよ。 # cut_here := "" # でも責任も取ってよ。 ギク!) cut_here := "<cut here" ################### # バンドル処理メイン ################### every list := !fn_list do { #ファイルリストから順に dir := open(list[1]) | stop("cannot open ",list[1]) #取り出し。 ################### # ヘッダー出力 ################### write(&errout,list[1]," ( ",list[3]," ",list[4]," )") c_fname := top_cut('\\',list[1]) # ディレクトリー部削除 str := head || c_fname || " ( date:" || list[3] || " time:" || list[4] || " ) " str := left(str,width,"-") # width = 0 でfailするので↑と分ける。 write(str || cut_here) ################### # ファイル本体出力 ################### n_line := 0 # 行数/ファイル n_word := 0 # 単語数/ファイル while line := read(dir) do { write(line) n_line +:= 1 n_word +:= *split(line,' \t') } # end of while close(dir) # 脱がせたら着せる。 # えっ。あれ〜? ################### # トレーラー出力 ################### str := trail || c_fname || " ( lines:" || n_line || " words:" || n_word || " ) " str := left(str,width,"-") write(str || cut_here) } # end of every ################### # おまけ(終わり表示) ################### write(&errout,"\t",*fn_list," file(s) bundled.") end -----$ IYAB2.ICN ( lines:75 words:264 ) --------------------<cut here -----^ TOP2.ICN ( date:96-12-01 time:22:30 ) ---------------<cut here # 文字列の 先頭から特定文字までの部分 を取り去る。最長部分を取り去る。 procedure top_cut(c,s) s ? { repeat { if cp := upto(c,s) then s:= s[cp +1 :0] else return s } } end # 文字列の 先頭から特定文字までの部分 を得る。最短部分を得る。 procedure top_get(c,s) s ? { if cp := upto(c) then return s[1:cp] else return s } end -----$ TOP2.ICN ( lines:15 words:47 ) ----------------------<cut here wild.icn iyab.icn 関係のファイル名で、後ろに 2という名前がついているのが多い のですが、これは私が元々使っていたプログラムに説明を付け加えたり、講座に関係の 無い procedureを削ったりしているファイルなもので、オリジナルと区別するため後ろ に 2を加えたファイル名としているという訳で... それでは、第18回はこの辺で。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 瞳水晶/遊佐未森 BGD: 大関のものも BGS: Mild Seven Menthol (icon_18.txt) ■ Icon > Icon入門講座(19)vanlog.icn 風つかい 目次へ プログラム例の説明も今回で終わりです。 では、19回、いきます。 このプログラムは、pcvanのログファイルからメッセージを抜き出すものです。 メッセージを抜き出すだけなら、YOTさんの ygrepでpv.patを使えば高速に抜き 出せます。 私もずっと ygrepのお世話になっていましたが、pcvanのログで不便な点を解消 しようと、このプログラムを作りました。 pcvanのタイトル形式では、メッセージタイトルの先頭に識別記号がついていな いので、メッセージタイトルで検索してタグファイルを作るのが面倒なのです。 で、メッセージを抜き出すついでに、メッセージタイトルの先頭に記号つけるように しました。(記号は"■ "としています。) これで、ygrep -tg "■ " van1201.lop | irep elis でメッセージタイトルをもとに 簡単にタグジャンプできるようになりました。 ま、そんなためのプログラムです。 -----^ VANLOG2.ICN ( date:96-12-01 time:23:18 ) ------------<cut here ######################################## # PCVANのログファイルからメッセージを抜き出すフィルター。 # ygrep の PATを使えば速いが、Iconプログラムの勉強のため作成。 # Ver1.1 1996/11/04 Ver.1.2 1996/12/01 ######################################## # # サンプルログ(pcvanのSIG書込みの開始) ##1007/1007 テキストデータ処理 #★タイトル (TRA11936) 96/10/13 14:52 (175) #■ Icon >月別書き込み数集計 風つかい #★内容 # # サンプルログ(インターネットニュースの開始) #Article 10 (561/561) in comp.lang.icon: # # サンプルログ(書込み・ニュースの終わり) #番号またはコマンド ################## link van_ln22, strings2, top2, wild2 procedure main(args) Usage := "Usage: vanlog2 van????.log" if *args = 0 then stop(Usage) # ファイル指定無し。 else fn_list := wild(args) | stop(Usage) # コマンド行解析 every list := !fn_list do { # ファイルリストから順に f_name := list[1] # ファイル名を取り出す。 if map(top_cut('\.',f_name)) == "log" # 拡張子"log"チェック then f_out := (top_get('\.',f_name) || "\.lop") # 出力先ファイル名生成 else stop("file_extention is not <<log>>") # エラーメッセージ # ログファイルオープン dir := open(f_name) | stop("cannot open ",f_name) # 出力ファイルオープン out_dir := open(f_out,"a") | stop("cannot open ",f_out) write(&errout,top_cut('\\',f_name)," -> ",top_cut('\\',f_out)) # モニタ # ファイルから1行づつ読み込んで、処理モードに従い処理。 while line := read(dir) do { write(out_dir,van_line(deletec(line,'\^M'))) # 単独CRを削除した行データ } # の処理結果を出力 write(&errout) close(dir) # ログファイルクローズ close(out_dir) # 出力ファイルクローズ } end -----$ VANLOG2.ICN ( lines:48 words:146 ) ------------------<cut here -----^ VAN_LN22.ICN ( date:96-12-01 time:23:19 ) -----------<cut here ################## # pcvan のログの1行処理 # メッセージブロックを検出して、メッセージ行なら返す。さもなくば失敗。 ################## link match2 procedure van_line(line) static mode, st_pat1, st_pat2, end_pat1, sub_pat initial { # 処理モード初期化 mode := 0 # 0: search header # 1: ★タイトル # 2: message title # 3: ★内容 # 4: message body #11: news body st_pat1 := ["#",&digits,'/',&digits] # 先頭パターン(のリスト) st_pat2 := ["Article ",&digits,&digits ++ ' ()/',"in "] # # 兼末尾パターン end_pat1 := ["番号または"] # 末尾パターン(のリスト) sub_pat := ["Subject:"] } case mode of { 0 : { if L := em_match(st_pat1,line) then { # サーチパターンと一致 # em_matchはサーチパターン文字が連続的に # 出現すれば成功し、出現ポジションをリス #トにして返す。出現しなければ失敗。 mode := 1 writes(&errout,line[1:L[3]]," ") # return line } if L := em_match(st_pat2,line) then { mode := 11 writes(&errout,line[1:L[3]]," ") # return line } fail } 1 : { mode := 2 return line } 2 : { mode := 3 write(&errout,line) # メッセージタイトルを出力、動作モニター用CRT出力 return if line[1:5] == (ss := "■ ") then line else ss || line } 3 : { mode := 4 return line } 4 : { if em_match(end_pat1,line) then { mode := 0 fail } if L := em_match(st_pat1,line) then { writes(&errout,line[1:L[3]]," ") mode := 1 return line } return line } 11 : { if em_match(end_pat1,line) then { mode := 0 fail } if L := em_match(st_pat2,line) then { writes(&errout,line[1:L[3]]," ") return line } if em_match(sub_pat,line) then write(&errout,line) return line } } # end of case end -----$ VAN_LN22.ICN ( lines:75 words:223 ) -----------------<cut here match.icnを作りだしてから、やっぱ、biplの正規表現ライブラリーを使えば よかったと思いました。 正規表現は偉大だ。 -----^ MATCH2.ICN ( date:96-12-01 time:23:04 ) -------------<cut here # 文字列のパターン照合 procedure em_match(m_list,line) # exact many type match # m_list の中の文字・文字列が順に現れたら成功。 #(間があいてはいけない。) # 一致開始ポジションと最後文字の終了ポジションを返す。 list := [] # return用リスト /line := &subject # 指定が無ければ &subject pe := 0 # 先頭検出用 line ? { every i := 1 to *m_list do { # パターンリストから順次取り出し case type(m := m_list[i]) of { # パターンのタイプを調べる。 "cset" : { tab(ps := upto(m)) | fail # 文字の時は upto関数 if pe = 0 & ps ~= 1 then fail # 文字列先頭でないと失敗 if pe ~= 0 & ps ~= pe then fail # 続いていないと失敗 tab(pe := many(m)) } "string" : { tab(ps := find(m)) | fail # 文字列の場合は find関数 if pe = 0 & ps ~= 1 then fail # 文字列先頭でないと失敗 if pe ~= 0 & ps ~= pe then fail # 続いていないと失敗 tab(pe := ps + *m) } default : fail } # end of case put(list,ps) # リストへ文字(列)開始位置を格納 } # end of every put(list,pe) # 最後の文字(列)終了位置を格納 } return list end -----$ MATCH2.ICN ( lines:30 words:155 ) -------------------<cut here それでは、第19回はこの辺で。 次回のむすびでおしまいになります。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 瞳水晶/遊佐未森 BGD: 大関のものも BGS: Mild Seven Menthol (icon_19.txt) ■ Icon > Icon入門講座(20)むすび 風つかい 目次へ AWKer のための Icon入門講座 と副題をつけるべきだったな〜と思いつつ、私の知識 の範囲でのIconの説明を終わります。 最初に、テキスト(文章)解析言語といっておきながら、文章解析の話が全然でて こないぞ。 と、お思いでしょう。 Icon自体は、その機能を備えているのですが、私が使いこなしていないのもので.. Icon教典には、文章解析の例がでてくるのですが、よく理解できておりません。 私が使えない機能が未だ沢山あります。 ・バックトラッキング関係の機能は、ジェネレータとsuspend 以外にもあるのです が、手に負えません。 ・現時点では、グラフィック関係は Unix版で X-Windowを動かさないと無理みたい ですので試していません。 Linux あたりが、使える環境になりましたら試してみたいのですが。 でも、グラフィックの説明なんて、テキスト文章の範囲で、できるかしら。 この講座を読まれて、 ・Iconを使ってみよう。 とか、 ・Iconを極めてみよう。 とか、 ・講座の文章や例が分かりにくいからもっとわかりやすく書き換えてあげよう。 とか ・抜けている分の講座を作ってやろう。 とか お考えの方がいらっしゃると、とてもうれしいです。 ・アリゾナ大学へ留学してみよう。 とか ・今度の海外旅行は、アリゾナへいこう。 というんでも、ま、いっか。 ちなみに、アリゾナ大学は、西部劇では割とでてくるツーソンというところにあり ます。 http://www.cs.arizona.eduから、アリゾナ大学紹介 →Tucson の紹介へと たどれます。 それではIcon入門講座を終わります。長文におつきあいいただきまして、ありがとう ございました。 では、またお会いする日まで。 【転載・編集自由】 風つかい (TRA11936@pcvan.or.jp) BGM: 瞳水晶/遊佐未森 BGD: 茉莉花茶 BGS: Mild Seven Menthol (icon_20.txt)