ikhr.net

Luaの標準入力で数値入力した直後の行入力が実行されない

NeovimLuaのランタイムを最初から同梱していることを知ったので、最近Luaを学んでいます。Hammerspoonとかも、設定をLuaで書くんですよね。

プラグインのように、プロダクト本体を拡張するための小規模なコードをカジュアルに書きたい、でも速度は犠牲にしたくないという、物事の隅っこに棲息する需要は必ず発生します。Luaは、そういった用途に割り切った言語でないかと思います。

練習がてらAtCoderの簡単な例題を解いていました。AtCoderはプログラミングコンテストを開催するサービスです。問題文に記載のある指定された形式のデータを標準入力から与え、加工した結果を標準出力に流します。出力結果が合っていれば正解となります。

ということで、Luaでの入出力の書き方にいきなり直面する訳ですが、最初の問題ではまってしまいました。

この問題では3行の入力が与えられます。1行目は整数1個ですが、2行目はスペースを挟んで整数2個です。3行目は文字列が入力されます。

1
2 3
test

出力は上の例で言うと、 123 を足した結果と test を、スペースを挟んで出力します。

6 test

そこで以下のコードを書きました。

#!/usr/bin/env lua

local a, b, c = io.read('n', 'n', 'n')
local s = io.read('l')
print(a + b + c .. ' ' .. s)

io.read() の引数を 'n', 'n', 'n' とすることで、数値を3つ変数に取り込んでくれます。

1行に数値が3つあっても構いません。

1 2 3

1行に1つずつでも構いません。

1
2
3

間に空行を挟んでも問題ありません。

1



2 3

ここまでは柔軟性があり便利なように思えます。

また、 io.read('l') で行全体を受け取ってくれます。

権限を与えて実行します。すると以下の結果になります。

$ chmod u+x ./practice_1.lua
$ ./practice_1.lua
1
2 3
6

2 3 と入力して return を押した時点で 6 が返ります。 test を入力するタイミングがありませんでした。

奇妙な挙動で手こずりましたが、何とか情報を見つけることができました。

先ほど述べましたが、数値っぽいものが3つ見つかるまでは、ユーザーは標準入力で空行を何行入力しても構いません。裏を返すと io.read('n') にとって、改行には特別な意味がないということになります。

数値入力の流れを明示的に断ち切るためにLuaが io.read('l') を1つ消費しているようです。本来は文字入力をするための記述が、数値入力に奪われるため、文字入力のための待ち受けが生じなかったということになります。この問題を回避するには、次のように末尾の 'n' の後ろに 'l' を置きます。

#!/usr/bin/env lua

local a, b, c = io.read('n', 'n', 'n', 'l')
local s = io.read('l')
print(a + b + c .. ' ' .. s)

釈然としない仕様ですが、これで意図した通りに動くようになりました。


...