Closed5
色々なプログラミング言語でinput-loop
はじめに
input-loopとは?
ここでは以下に挙げるようなものをいう:
- 標準入力ストリームを標準出力ストリームへコピーする。
- 行単位でストリームから読み込み、行単位でストリームへ書き出す。
- end-of-file (EOF) に到達したら終了する。
方針
- 実行可能ファイルとして定義する。
- インタプリタ型言語はファイルの先頭にshebangを付与する。
- コンパイル型言語はコンパイルする。
- chmod u+x
- その言語“らしさ”を求める。
- 実行速度、実行効率などは特段突き詰めない。
- 簡素に記述する。
- 対話環境が用意できるものでワンライナーで記述できる言語は併せて記述する。
見本
-
sed
コマンドをUnix shellで実行した時の振る舞いを見本とする。 - 以下の
./executable
をsed
に置き換えても成り立つ。
sample
$ echo foo | ./executable⏎
foo
$
sample
$ ./executable⏎
foo⏎
foo
bar⏎
bar
^D
$
sample
$ ./executable < input.txt⏎
金魚は青空を食べてふくらみ
鉢の中で動かなくなる
鳩だか 鉢のガラスにうすい影を走らせる
來たのは花辨か 白い雲の斷片
$
input.txt
金魚は青空を食べてふくらみ
鉢の中で動かなくなる
鳩だか 鉢のガラスにうすい影を走らせる
來たのは花辨か 白い雲の斷片
参考
Python
input-loop.py
#!/usr/local/bin/python3
import sys
def main():
while (line := sys.stdin.readline()):
sys.stdout.write(line)
if __name__ == '__main__':
sys.exit(main())
REPL
>>> import sys⏎
>>> while (line := sys.stdin.readline()): sys.stdout.write(line)⏎
... ⏎
別解
REPL
>>> import sys⏎
>>> [print(line, end="") for line in sys.stdin]⏎
説明
- 中核の部分は割と見たまんまな書き方・あじわい。
- なんとなく対称性を感じられて好き。
-
line := sys.stdin.readline()
の部分はPython 3.8から導入されたAssignment Expressions[1]。 -
sys.stdin.readline
メソッドは、行末の改行を含めて返す。 -
sys.stdout.write
メソッドは、引数に取った文字列の行末に改行を加えずに書き込む。 - そういうわけで、
sys.stdin.readline
してsys.stdout.write
すると問題なくinput-loopを達成できる。 - これらのメソッドと組み込み関数の
input()
とprint()
とではそれぞれ微妙に振る舞いが異なる。- したがって、単純にこれらを入れ替えて代用することはできない。
- ワンライナーではPythonの文法の制約を受けて[2]
while
statementとimport
statementを同じ行に書くことはできない。 - ワンライナーでは入力行をechoした後にその書き出された文字数まで端末へ出力されるのが厄介。
- 気に入らなければ、
sys.stdout.write(line)
はprint(line, end = "")
で置換可能。
- 気に入らなければ、
- 別解はリストの内包表記を利用した書き方。
C
input-loop.c
#include <stdio.h>
int main(int argc, char const *argv[])
{
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, stdin)) > 0)
fwrite(line, linelen, 1, stdout);
return 0;
}
説明
- (書き方はこれで合ってんのかな…)と自信を持てないくらい書き慣れない者にとってはCって難しい。
- 一応コンパイルして検証済み。
-
getline(3)
のBSD Library Functions Manual[1]のEXAMPLESセクションに記載されていた例が役立った。 - ストリームから1行だけ読み取るというと
gets(3)
などが挙げられる-
gets(3)
はISO C99に適合しているが、C11以降は廃止となっている。
-
Unix shell (sh)
input-loop.sh
#!/bin/sh
while read -r -- line
do
printf -- '%s\n' "${line}"
done
ワンライナー
$ while read -r line; do printf '%s\n' "${line}"; done⏎
説明
- たぶんIEEE Std 1003.1準拠。
-
read
コマンドの-r
--
- 外部コマンドの呼び出しに変えるとオーバーヘッドが増大する。
C#
input-loop.cs
using System;
namespace InputLoop
{
public class Program
{
public static void Main(string[] args)
{
Console.OpenStandardInput().CopyTo(Console.OpenStandardOutput());
}
}
}
input-loop.cs (.NET 6 / C# 10)
namespace InputLoop;
Console.OpenStandardInput().CopyTo(Console.OpenStandardOutput());
説明
- 中核部分は読んで字の如く、「(システムの)操作卓の標準入力を開いて、それを同じ標準出力へ複製する」という素直な陳述。
- ループもないし、「読め」「書け」という命令もない。
- これがオブジェクト指向プログラミングですか。
- 前者は伝統的な記法に則っている。外側の部分は質実剛健な感じ。悪くいえば冗長っぽい。
- 一方で後者のように、最近では簡潔な書き方もできるようになっている。
このスクラップは2023/08/11にクローズされました