質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

2回答

3025閲覧

Go言語で標準入力を1文字ずつ取得したい

退会済みユーザー

退会済みユーザー

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2020/09/11 10:21

こんにちは。
Go言語で標準入力から1行ごとではなく、1文字ずつ取得する方法を知りたいです。Enterではなく、1文字入力するごとにfmt.Printlnで出力しようと思っているのですが、どのようにすればいいのかわかりません。

ご教授、お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

注意:ここに書いたのは連続する標準入力を一文字づつ処理する方法です。
ターミナルは基本の挙動がEnter押すごとに標準入力に投入します。

ASCII文字しか扱わないなら1バイト長のbyteスライスを引数にしたReadでOKです。

go

1b := []byte{0} 2_, err := os.Stdio.Read(b) 3...

ただこれだと、ASCII以外の文字で1文字づつになりません。
こういった場合でも正しく「1文字」ずつ読みたいのなら、
例えばbufio.ReaderのReadRuneを使います。

go

1package main 2 3import ( 4 "bufio" 5 "fmt" 6 "io" 7 "log" 8 "os" 9) 10 11func main() { 12 reader := bufio.NewReader(os.Stdin) 13 for { 14 r, _, err := reader.ReadRune() 15 if err != nil { 16 if err == io.EOF { 17 return 18 } 19 log.Fatal(err) 20 } 21 fmt.Println(string(r)) 22 } 23}

追記

質問者のコメントにあるような文字単位の入力をプログラムで受け取るには
OSのAPIを利用するか、以下のようにターミナルの動作モードを変えるしかなさそうです。
(以下の例はmacOSまたはLinux向けの方法です)
また、このモードではターミナルがCtrl+Cを受け取ってプロセスにSIGINTを送る機能も無効になるので
止めるには外部からシグナルを投げるかプログラム自身に終了処理が必要です。

https://play.golang.org/p/75GhzqTfV4_L

go

1package main 2 3import ( 4 "bufio" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "os/exec" 10 "os/signal" 11) 12 13func main() { 14 cmd := exec.Command("stty", "raw") 15 cmd.Stdin = os.Stdin 16 cmd.Run() 17 defer func() { 18 cmd := exec.Command("stty", "-raw") 19 cmd.Stdin = os.Stdin 20 cmd.Run() 21 }() 22 reader := bufio.NewReader(os.Stdin) 23 sig := make(chan os.Signal, 1) 24 signal.Notify(sig, os.Interrupt) 25 go func() { 26 defer close(sig) 27 for { 28 r, _, err := reader.ReadRune() 29 if err != nil { 30 if err == io.EOF { 31 return 32 } 33 log.Fatal(err) 34 } 35 if r == 'q' { 36 break 37 } 38 fmt.Println(string(r)) 39 } 40 }() 41 <-sig 42}

投稿2020/09/13 12:25

編集2020/09/14 00:42
nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/13 13:27

ご回答ありがとうございます。Enterを押さないと以下のように読まれないません。 ``` go run ./main.go hello(Enter) h e l l o ``` 以下のように、1文字ずつやりたいのですが、どのようにしたらできますでしょうか。 ``` go run ./main.go h => h e => e ... ```
nobonobo

2020/09/13 21:59

おお。それは標準入力では処理できません。ターミナルの機能またはGUI機能を呼ぶ必要があります。この場合OSがなんなのかに依存したりするのでなんのOSをお使いなのか追記ください。
退会済みユーザー

退会済みユーザー

2020/09/14 08:57

失礼いたしました。私はmacOSを使用しております。
guest

0

こういうことでしょうか。

go

1package main 2 3import ( 4 "fmt" 5 "log" 6 7 "github.com/mattn/go-tty" 8) 9 10func main() { 11 tty, err := tty.Open() 12 if err != nil { 13 log.Fatal(err) 14 } 15 defer tty.Close() 16 17 for { 18 r, err := tty.ReadRune() 19 if err != nil { 20 log.Fatal(err) 21 } 22 fmt.Println("Key press => " + string(r)) 23 } 24}
//go.mod module sample/tty go 1.16 require github.com/mattn/go-tty v0.0.3

shellsession

1$ go run . 2Key press => a 3Key press => b 4Key press => c 5Key press => d 6Key press => e 7...(ctrl+c) 8signal: interrupt 9$

かの mattn さんの go-tty を使って、私の x86_64 系 *nix でビルドされたバイナリ動きました。未検証ですが Windows でもイケるらしいですよ。

動作確認済み環境:

  • macOS Catalina(10.15.7), Linux 上で darwin 用にビルドしたバイナリ実行
  • Debian GNU/Linux 10 (buster), go version go1.16.2 linux/amd64
  • Alpine Linux v3.13, go version go1.16 linux/amd64

投稿2021/03/15 11:26

KEINOS

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問