Luaの標準入力で数値入力した直後の行入力が実行されない
NeovimがLuaのランタイムを最初から同梱していることを知ったので、最近Luaを学んでいます。Hammerspoonとかも、設定をLuaで書くんですよね。
プラグインのように、プロダクト本体を拡張するための小規模なコードをカジュアルに書きたい、でも速度は犠牲にしたくないという、物事の隅っこに棲息する需要は必ず発生します。Luaは、そういった用途に割り切った言語でないかと思います。
練習がてらAtCoderの簡単な例題を解いていました。AtCoderはプログラミングコンテストを開催するサービスです。問題文に記載のある指定された形式のデータを標準入力から与え、加工した結果を標準出力に流します。出力結果が合っていれば正解となります。
ということで、Luaでの入出力の書き方にいきなり直面する訳ですが、最初の問題ではまってしまいました。
この問題では3行の入力が与えられます。1行目は整数1個ですが、2行目はスペースを挟んで整数2個です。3行目は文字列が入力されます。
1
2 3
test
出力は上の例で言うと、 1
と 2
と 3
を足した結果と 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)
釈然としない仕様ですが、これで意図した通りに動くようになりました。