https://twitter.com/nunnun/status/1698607615184666947 の telnet による電子公告がトレンドに入っていたのをみかけたので、 macOS の端末の設定を Shift_JIS にして telnet コマンドで確認した後、 Ruby で UTF-8 の端末のまま確認できるようにプログラムを書いて確認してみました。

動作確認環境

最近の環境ならどこでも動くはずなので、大雑把に書いておきます。

  • Linux, macOS
  • Ruby 3.1, 3.2

プログラム

以下の内容を適当なファイルに保存して実行してみてください。

#!/usr/bin/ruby
# frozen_string_literal: true

require 'socket'

sock = Socket.tcp('koukoku.shadan.open.ad.jp', 23)
sock.set_encoding(Encoding::SJIS, Encoding::UTF_8)

last_read_time = Time.now
Thread.new do
  sleep 1 while 1 > (Time.now - last_read_time)
  sock.close_write
end

sock.each_char do |c|
  last_read_time = Time.now
  STDOUT.putc c
end

解説

最初の 4 行は Socket を使うためなどのお約束なのでいいとして、 ソケットオブジェクトの作成は TCPSocket ではなく Socket.tcp を使ってみました。

一番重要なエンコーディングの変換は sock.set_encoding(Encoding::SJIS, Encoding::UTF_8) で Ruby に任せています。

次に切断処理用のスレッドを作成しています。 表示が終わったっぽいところで自分で Control+C などで止めるなら不要なのですが、 プログラムにするなら自動で切れた方が良さそうということで、 何も送られてこなくなってそうだったら、 close_write で書き込み側を閉じて、 向こうから切断してもらうようにしました。

読み込み部分本体は each_char で 1 文字ずつ読んで出力することで、 遅さの演出もそのまま見えるようにしました。

IO.copy_stream(sock, STDOUT) だと文字化けしました。

感想

重要なのは set_encodingeach_char のループだけなので、簡単に書けるかなと思ったら、 表示が終わった後に自動で切断されなかったので、その処理で思ったより長くなってしまいました。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published