🌊

[Ruby] 標準入力を受け付ける際に ^H などの ASCII 制御文字を意図した通りに認識させる

2021/03/02に公開

結論

STDIN.gets ではなく Readline.readline を使おう

STDIN.gets

Ruby で標準入力を受け取る方法を調べると、多くの場合、以下の実装方法が出てきます。

stdin.rb
print '> '
text = STDIN.gets.strip
puts "You said #{text}!"
$ ruby stdin.rb
> hello
You said hello!

gets の他にも readreadlinereadlines があるようです。
Ruby 標準入力から複数行読み取りたい

欠点

しかし、上記の方法だと ASCII 制御文字を意図した挙動で認識させることができません。

$ ruby stdin.rb
> hello^H^H^H
You said he!lo

上記の例では、hello と入力したあとに、ASCII 制御文字の backspace (ctrl + H で入力可能) を 3 回入力しています。

本当は hello と入力したあとに 3 回 backspace の制御文字を入力しているので he となってほしいのですが、hello^H^H^H となってしまい、標準入力の受け付けを終了したあとに backspace が適用されています。

解決方法

これを意図した通りにするためには以下のように実装します。

readline.rb
require 'readline'

print '> '
text = Readline.readline
puts "You said #{text}!"
$ ruby readline.rb
> he # "hello" と入力したあとに ctrl + H を 3 回押した
You said he!

その他

Readline.readline は、他にもヒストリを使うことができたりして便利です。カーソルの上キーや ctrl + P を押すと、前に入力した文字列を表示することができます。詳しくは module Readline のリファレンスマニュアル を参照ください。

ASCII 制御文字については Wikipedia をご覧ください。

GitHubで編集を提案

Discussion