どなたかその他の(スクリプト)言語による例をお願いいたします(^o^)/
{ if($1!=0) total+=$1; else exit; }
END{ print "total = ", total; }
実行方法
gawk -f add.awk
Tclの場合の一例を紹介します。上記と同様、数値が入力されているかなど、 細かなチェックはしていません。
一般的なTclのスクリプト起動のやりかた(最初の3行)から、ちょっと余計な機能を足しました。
スクリプト: addition.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
# 初期値
set total 0
# コマンド引数の読み込み
if {$argc} {
foreach value $argv {
set total [expr $total + $value]
}
}
# 0が入力されるまでループ
while {[set value [gets stdin]] != 0} {
set total [expr $total + $value]
}
# 合計を出力
puts "合計:$total"
exit
実行方法
LinuxなどUNIX系シェル上で実行するには、次のようにします($はシェルのプロ
ンプトです)。
$ chmod +x ./addition.tcl $ ./addition.tcl 2 4 6 8 10 0 合計:30(実行時に引数を付けてもOK)
$ ./addition.tcl 2 4 6 8 10 0 合計:30
あまり凝った作りにしてもなんですが、数値判定のルーチンを追加しました。
Tclではcatchコマンドを使って演算エラーを検出する方法が簡単ですが、練習用 にと正規表現を使ってみました。1.2345e+67のような指数形式には今回対応して いません。
なお、今回使った正規表現はチェックが不十分なので無駄や欠陥があるかもしれ ません。どうも無責任ですみません。
スクリプト: addition2.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
# add_number
# n = n + m を計算する
proc add_number {n m} {
# 実数または整数であるかチェック
if {[regexp {^[-+]?[0-9]+\.*[0-9]*$} $m]} {
return [expr $n + $m]
} else {
puts "${m}は数字でないため、スキップしました。"
return $n
}
}
#-------
# メイン
# ------
# 初期値
set total 0
# コマンド引数の読み込み
if {$argc} {
foreach value $argv {
set total [add_number $total $value]
}
}
# 0が入力されるまでループ
while {[set value [gets stdin]] != 0} {
set total [add_number $total $value]
}
# 合計を出力
puts "合計:$total"
exit
実行方法
$ chmod +x ./addition2.tcl $ ./addition2.tcl -2.5 2e+5 2e+5は数字でないため、スキップしました。 4.5 +6.5 8 10. 0 合計:26.5
所詮TclはTclらしく、ということでcatchコマンドを使った例です。
スクリプト: addition3.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
# add_number
# n = n + m を計算する
proc add_number {n m} {
if {[catch {set n [expr $n + $m]} errmsg]} {
puts $errmsg
}
return $n
}
#-------
# メイン
# ------
# 初期値
set total 0
# コマンド引数の読み込み
if {$argc} {
foreach value $argv {
set total [add_number $total $value]
}
}
# 0が入力されるまでループ
while {[set value [gets stdin]] != 0} {
set total [add_number $total $value]
}
# 合計を出力
puts "合計:$total"
exit
実行方法
$ chmod +x ./addition3.tcl $ ./addition3.tcl -2.5 2e-2 2e syntax error in expression "-2.48 + 2e" 4.5 +6.5 8 10. 0 合計:26.52
Tcl/Tk8.1以上では次のように記述することも出来ます。自分自身は通常のコー ディングにおいて、ここまで日本語名を多用しませんが、やろうと思えばここま でできる、という参考にと紹介しました。
スクリプト: addition4.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
# 加算処理
# 「数1 = 数1 + 数2」を計算する。
# Tclでは全てコマンドとして処理されるので
# +=のような代入演算子がありません。
proc 加算処理 {数1 数2} {
if {[catch {set 数1 [expr ${数1} + ${数2}]} エラー]} {
puts ${エラー}
}
return ${数1}
}
#-------
# メイン
# ------
# 初期値
set 合計 0
# コマンド引数の読み込み
if {$argc} {
foreach 引数 $argv {
set 合計 [加算処理 ${合計} ${引数}]
}
}
# 0が入力されるまでループ
while {[set 入力値 [gets stdin]] != 0} {
set 合計 [加算処理 ${合計} ${入力値}]
}
# 合計を出力
puts "合計:${合計}"
exit
はじめ last でなくて break って書いてしまった (^_^;
スクリプト: add.pl
#!/usr/bin/env perl
while (<>) {
if ($_ != 0) {
$total += $_;
} else {
last;
}
}
print "total = $total\n";
実行方法
perl add.pl
スクリプト: add.pl
#!/usr/bin/env perl
while (@ARGV) {
$total += shift(@ARGV);
}
while (<>) {
if ($_ != 0) {
$total += $_;
} else {
last;
}
}
print "total = $total\n";
スクリプト: add.pl
#!/usr/bin/env perl
while (($v = <>) != 0) {
$total += $v;
}
print "total = $total\n";
スクリプト: add.py
#!/usr/local/bin/python
from sys import argv
from operator import add
sum = reduce(add, map(int, argv[1:]), 0)
while 1:
buf = raw_input()
if buf == '0': break
sum += int(buf)
print sum
そも、input()という標準関数があるので、stdinなんて インポートする必要ないです。
input関数は文字でなく「Python文」を受け取りますので、 値さえあればOKなので、実は「リテラル」でもよいわけでして、 これで、「文字列→数値変換」も全く必要ありません。
※文字を受け取りたい場合はraw_input()を利用。
ただし、ファイル入力で、入力ファイル名をオプションから 受け取ろうとすると、こうなります。
スクリプト: add2.py
import sys f = open(sys.argv[1],"r") i = 1 s = 0 while i: i = int(f.readline()) s += i print "Total %i yen" % s
Pythonの場合、基本はコレで十分。
スクリプト:
i = 1
s = 0
while i:
i = input(">>> ")
s += i
print "Total %i yen" % s
実行方法
Windowsでダブルクリック起動の場合は、
raw_input()の1行を最後にいれておくと、Enterキーを押すまでウィンドウが 消えません。
UNIXの場合は、
#! /usr/bin/pythonで、実行形式にしてもいいけど、Pythonに直接渡した方が簡単かも・・・
bashやzshやkshならexprを使わずに
sum=$(($sum + $line))と書けます。bashかzshなら
sum=$[$sum + $line]とも書くこともできます。
スクリプト:
#!/bin/sh sum=0 while read line do if [ $line = 0 ]; then break; fi sum=`expr $sum + $line` done echo "total = $sum"
MIT で アリゴリズムの講義に使われる Scheme の例です. (初心者の言語とはいいがたいけど参考までに)
;;; 解1
;;; 名前付き let による終端再帰を使った素直な解
(display
(let loop ((total 0))
(let ((num (read)))
(if (zero? num)
total
(loop (+ total num))))))
;;; 解2
;;; 継続の呼び出しでループから脱出するマニアな解
(display
(let ((total 0))
(call-with-current-continuation
(lambda (break)
(let loop ()
(let ((num (read)))
(if (zero? num)
(break total)
(begin
(set! total (+ total num))
(loop)))))))))
;;; 解3
;;; 継続の呼び出しでループを実現するひねくれた解
(display
(let ((total 0))
(let ((next (call-with-current-continuation (lambda (k) k))))
(let ((num (read)))
(if (zero? num)
total
(begin
(set! total (+ total num))
(next next)))))))
;;; 解4
;;; 解2と解3を組み合せてループとループからの脱出を
;;; ともに継続で実現した病的な解
(display
(let ((total 0))
(call-with-current-continuation
(lambda (break)
(let ((next (call-with-current-continuation (lambda (k) k))))
(let ((num (read)))
(if (zero? num)
(break total)
(begin
(set! total (+ total num))
(next next)))))))))
;;; 解5
;;; do を使った Scheme らしからぬ解
(display
(do ((num (read) (read))
(total 0 (+ total num)))
((zero? num) total)))
(let ((loop t) (total 0)) (while loop (setq num (read-minibuffer "")) (if (= num 0) (progn (setq loop nil) (message (format "%f" total)) (sleep-for 2)) (setq total (+ total num)) )))実行方法 最後のかっこの直後で Ctrl-x Ctrl-e
Emacs Lisp でも Tcl と同じく Catch & Throw が使えますから, 以下も,解です.
(message (format "%f" (catch 'break (let ((total 0)) (while t (let ((num (read-minibuffer ""))) (if (= num 0) (throw 'break total) (setq total (+ total num)))))))))
Common Lisp も Scheme とは異なり, 正しい終端再帰を実装していませんでした.
で,Common Lisp の場合です.
;;; 解1
;;; do を使った場合
(print
(do ((num (read) (read))
(total 0 (+ total num)))
((zerop num) total)))
;;; 解2
;;; loop を使った場合
(print
(let ((total 0))
(loop
(let ((num (read)))
(when (zerop num) (return total))
(setq total (+ total num))))))
スクリプト: add.rb
#! /usr/local/bin/ruby
sum=0
while 1
print "数値を入力 > "
break if (num=gets.to_f)==0
sum+=num
end
puts "数値の合計は #{sum} です"
実行方法
ruby add.rb
ついでにみようみまねで覚えた csh の場合、
スクリプト:
#! /bin/csh set num=1 set sum=0 while ($num != 0) echo -n "数値を入力 > " set num = $< @ sum = $sum + $num end echo "数値の合計は $sum です"
TeX Book で Knuth 先生は,
「特殊な効果が欲しいときや, コンピュータの使用料金をあまり気にしなくていいときには, 実際に TeX をプリミティブなプログラミング言語として活用してみるのもいい だろう.」
と述べておられます.(ASCII 版訳本より抜粋)
で,こんなになります.
スクリプト: add.tex
\newcount\total=0
\newif\ifcont
\loop
\message{ Please Input Integer>> }
\read-1 to\answer
\ifnum0=\answer
\contfalse
\else
\advance\total by \answer
\relax
\conttrue
\fi
\ifcont
\repeat
\message{ Total is \the\total}
\end
実行方法
これを TeX にかけると
端末から整数の入力を受けつけ,
端末に結果を出力した後,
空ページの dvi ファイルと
入力記録も含めた log ファイルを作ります.
TeXが出てきたからには、sed版も公開せねばなるまい。 # これが病的と呼ばれる一因か?! (^_^)
ちなみに負の数は実装していませんが、小数や多倍長演算はできます。
スクリプト: addition.sed
s/^ +//
s/ +$//
/^[0-9.][0-9.]*$/!q
/^0$/{
x
s/^/total = /
q
}
x
/^$/d
G
s/\n/ /
s/$/=/
t nop
:nop
:split1
s/^\([0-9]*\.\)\([0-9]\)\([0-9]*\) \([0-9]*\.\)\([0-9]\)\([0-9]*\)=\(.*\)/\1\3 \4\6=\7 \2\5/
t split1
:split2
s/\.\([0-9]\)\(.*=.*\)/.\2 \1/
t split2
s/\.//g
s/=/=./
:split3
s/^\([0-9]*\)\([0-9]\) \([0-9]*\)\([0-9]\)=/\1 \3=\2\4 /
t split3
:split4
s/\([0-9]\)\([0-9]\)\(.*=\)/\1 \2\3/
t split4
s/=/ /
s/ */ /g
s/ \././
s/\. /./
:loop
s/^[^ ]/ &/
s/00*\([0-9]\)/\1/g
s/\([0-9]\)0/\1/g
s/11/2/g
s/12/3/g
s/13/4/g
s/14/5/g
s/15/6/g
s/16/7/g
s/17/8/g
s/18/9/g
s/\([ .][0-9]*\)19/1\10/g
s/21/3/g
s/22/4/g
s/23/5/g
s/24/6/g
s/25/7/g
s/26/8/g
s/27/9/g
s/\([ .][0-9]*\)28/1\10/g
s/\([ .][0-9]*\)29/1\11/g
s/31/4/g
s/32/5/g
s/33/6/g
s/34/7/g
s/35/8/g
s/36/9/g
s/\([ .][0-9]*\)37/1\10/g
s/\([ .][0-9]*\)38/1\11/g
s/\([ .][0-9]*\)39/1\12/g
s/41/5/g
s/42/6/g
s/43/7/g
s/44/8/g
s/45/9/g
s/\([ .][0-9]*\)46/1\10/g
s/\([ .][0-9]*\)47/1\11/g
s/\([ .][0-9]*\)48/1\12/g
s/\([ .][0-9]*\)49/1\13/g
s/51/6/g
s/52/7/g
s/53/8/g
s/54/9/g
s/\([ .][0-9]*\)55/1\10/g
s/\([ .][0-9]*\)56/1\11/g
s/\([ .][0-9]*\)57/1\12/g
s/\([ .][0-9]*\)58/1\13/g
s/\([ .][0-9]*\)59/1\14/g
s/61/7/g
s/62/8/g
s/63/9/g
s/\([ .][0-9]*\)64/1\10/g
s/\([ .][0-9]*\)65/1\11/g
s/\([ .][0-9]*\)66/1\12/g
s/\([ .][0-9]*\)67/1\13/g
s/\([ .][0-9]*\)68/1\14/g
s/\([ .][0-9]*\)69/1\15/g
s/71/8/g
s/72/9/g
s/\([ .][0-9]*\)73/1\10/g
s/\([ .][0-9]*\)74/1\11/g
s/\([ .][0-9]*\)75/1\12/g
s/\([ .][0-9]*\)76/1\13/g
s/\([ .][0-9]*\)77/1\14/g
s/\([ .][0-9]*\)78/1\15/g
s/\([ .][0-9]*\)79/1\16/g
s/81/9/g
s/\([ .][0-9]*\)82/1\10/g
s/\([ .][0-9]*\)83/1\11/g
s/\([ .][0-9]*\)84/1\12/g
s/\([ .][0-9]*\)85/1\13/g
s/\([ .][0-9]*\)86/1\14/g
s/\([ .][0-9]*\)87/1\15/g
s/\([ .][0-9]*\)88/1\16/g
s/\([ .][0-9]*\)89/1\17/g
s/\([ .][0-9]*\)91/1\10/g
s/\([ .][0-9]*\)92/1\11/g
s/\([ .][0-9]*\)93/1\12/g
s/\([ .][0-9]*\)94/1\13/g
s/\([ .][0-9]*\)95/1\14/g
s/\([ .][0-9]*\)96/1\15/g
s/\([ .][0-9]*\)97/1\16/g
s/\([ .][0-9]*\)98/1\17/g
s/\([ .][0-9]*\)99/1\18/g
/[0-9][0-9]/b loop
s/ //g
x
d
実行方法
sed -f addition.sed
Metafont の場合です.
log ファイルができるのでご注意を...
スクリプト: add.mf
total := 0; forever: message ">> "; num := scantokens readstring; exitif num = 0; total := total + num; endfor; show total; end実行方法
mf add.mf
さすがに文法が独特で,やっとできました.
さらに,Adobe のページにリファレンスマニュアルがあったので, 索引を調べたら,いいオペレータを見つけました.
スクリプト: add.ps
/buf 16 string def
/total 0 def
/fd (%stdin) (r) file def
{ %loop
/num fd buf readline pop cvr def
num 0 eq { exit } if
/total total num add def
} loop
total ==
quit
実行方法1 Linux の GNU Ghostscript 5.50 でのみ動作確認しました.
% gs -sDEVICE=nullpage -q add.ps実行方法2 Windows XP の GNU Ghostscript 7.04 での動作確認(閑舎)。
gswin32c -sDEVICE=nullpage -q add.ps
cmd.exeだと足し算もできます。
スクリプト: add.cmd
@echo off set sum=0 :loop set /p line= if (%line%) == (0) goto break set /a sum=%sum%+%line% goto loop :break echo total = %sum%
素直に書くと次のようになります。
スクリプト: add01.icon
####################
# 簡易足し算器 Icon版1
####################
# add01.icn Rev.1.0 2002/05/06 windy 風つかい H.S.
# Usage : add01 # 数字+改行入力、0+改行を入力すると総和を出力
# This file is in the public domain.
procedure main()
sum := 0 # 総和初期化
while line := read() do { # (標準入力から)入力を読み込んで
if line == "0" then break # "0"ならばループを抜ける
else sum +:= numeric(line) # そうでなければ、数値変換し足し込む
}
write("Total = ",sum) # 総和を出力
end
もっと短くしようとすると、こんな風かな。
スクリプト: add02.icon
####################
# 簡易足し算器 Icon版2
####################
# add02.icn Rev.1.0 2002/05/06 windy 風つかい H.S.
# Usage : add02 # 数字+改行入力、0+改行を入力すると総和を出力
# This file is in the public domain.
procedure main()
sum := 0 # 総和を初期化
while sum +:= numeric(("0" ~== read()))
# ↑数値変換して足す ↑読み込んだ値が 0でなければ
write("Total = ",sum) # 総和を出力
end