コンソールの標準入力から読み取る方法は?


270

コマンドラインから標準入力を読み取りたいのですが、入力を求めるプロンプトが表示される前にプログラムが終了するため、試行が終了しました。C#でConsole.ReadLine()に相当するものを探しています。

これは私が現在持っているものです:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print("Enter text: ")
    text, _ := reader.ReadString('\n')
    fmt.Println(text)

    fmt.Println("Enter text: ")
    text2 := ""
    fmt.Scanln(text2)
    fmt.Println(text2)

    ln := ""
    fmt.Sscanln("%v", ln)
    fmt.Println(ln)
}

このコードは正しいようです。好奇心から、これをプレイグラウンドで実行していますか?Go Playgroundは、ネットワーク上の理由により、標準入力を許可していません。
LinearZoetrope 2014年

気にしないでください、それはあなたがポインタを必要とした微妙な問題のように見えます(私の答えを見てください)。しかし、bufio.NewReaderメソッドの問題は何が問題なのかはわかりません。
LinearZoetrope 2014年


8
混在させないでくださいbufio任意のリーダー(例えばのバッファリングをbufio.NewReader(os.Stdin)直接的には下線リーダー(例えばからの読み取りで)fmt.Scanln(x)から直接読み込みますos.Stdin)。バッファリングは、はるか先に任意に読み取る場合があります。(この特定のケースでは、後者はfmt.Fscanln(reader,x)同じバッファーから読み取る必要があります)。
Dave C、

fmt.Sscanln動作しません。実行すると "%v"になります
Beeno Tung

回答:


295

ブロックの何が悪いのかわからない

reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Println(text)

私のマシンで動作するように。ただし、次のブロックでは、入力を割り当てる変数へのポインターが必要です。で置き換えfmt.Scanln(text2)てみてくださいfmt.Scanln(&text2)Sscanlnstdinからではなく、すでにメモリ内にある文字列を解析するため、を使用しないでください。あなたがやろうとしていたことのようなことをしたいのであれば、それをfmt.Scanf("%s", &ln)

それでも問題が解決しない場合は、奇妙なシステム設定かバグのあるIDEが原因である可能性があります。


2
それらは単一引用符であるべきですか?ReadString('\n')またはReadString("\n")
425nesp 2014

8
@ 425nespはい、それが1バイトの区切り文字です。golang.org/pkg/bufio/#Reader.ReadString
LinearZoetrope 2014

3
良い答えですが、バックスペースなどのキーを使用しようとすると失敗します
kumarharsh

4
Golangがファイルからリーダーrdを介して変数に次のsように1行を読み取るためにif s,_ = rd.ReadString('\n'); true { s = strings.Trim(s, " \n") }
Nam G VU

2
面白いことだけを共有します(私はGolangの初心者です):\ nは単一引用符で囲む必要があります(二重引用符は使用しないでください)。それ以外の場合は、これを再現しますcannot use "\n" (type string) as type byte in argument to reader.ReadString
。– ivanleoncz

124

あなたも試すことができます:

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

if scanner.Err() != nil {
    // handle error.
}

6
1行だけの入力が必要な場合は、「for {}」を削除できます。
user2707671

3
for {}ループがある場合、入力時にループから抜け出す方法は?forループを停止させる特殊文字はありますか?-ありがとう
Madhan Ganesh

2
@Madhan scanner.Scan()は、forループを終了するかどうかを示すブール値を返します。
Helin Wang

5
入力が64 * 1024バイトより大きい場合、このエラーbufio.Scanner:token too longが発生します。またfmt.Println(scanner.Err())、forループの下に追加することを忘れないでください。
Yuvaraj Loganathan 2017

「abc \ n ^ D」と入力すると、期待される文字列は「abc \ n」ですが、「abc」が返されます。
Shivendra Mishra

96

これを行うためのより標準的な方法は次のようになると思います。

package main

import "fmt"

func main() {
    fmt.Print("Enter text: ")
    var input string
    fmt.Scanln(&input)
    fmt.Print(input)
}

見てくださいscangodocを:http://godoc.org/fmt#Scan

Scanは、標準入力から読み取られたテキストをスキャンし、連続するスペース区切り値を連続する引数に格納します。改行はスペースとしてカウントされます。

ScanlnはScanに似ていますが、改行でスキャンを停止し、最後の項目の後には改行またはEOFが必要です。


10
これは入力文字列のスペースが好きではないようです。
ヘアリークリス

3
@HairyChrisはい、これは奇妙です。文書では、stops scanning at a newline and after the final item there must be a newline or EOFスペースがなぜそれを「壊す」のかわからない、と書いてあります...私はそれがバグだと思います
karantan

6
このために開かれたバグがありました:github.com/golang/go/issues/5703それはWorkingAsIntendedとして閉じられました。関連項目:stackoverflow.com/questions/24005899/…groups.google.com/forum/#!topic/golang-nuts/r6Jl4D9Juw0多くの人がこれに問題を抱えているようです。ドキュメントの変更が必要ですか?また、その最後のリンクから:「ScanとScanlnは、そのような構文解析などのためのものです。そのため、stdinから1行のテキストを取得するだけでは目的が達成されません。」
user2707671

私にとっては、fmt.Scanの同様の関数のいずれかがbufio.NewReaderのようにスペースでうまく機能しないことは本当に混乱しています。
FilBot3

3
現在の2016 goバージョン(goバージョンgo1.6.2 linux / amd64)を使用fmt.Scanlnfmt.Scanている間も、スペースに関する同じ問題が残ります。
Chiheb Nexus 2016

30

コンソールからの入力を収集するには、常にbufio.NewScannerを使用してください。他の人が述べたように、仕事を行うにはいくつかの方法がありますが、スキャナーは本来その仕事をすることを目的としています。Dave Cheneyが、bufio.ReaderのReadLineではなくScannerを使用する理由を説明しています。

https://twitter.com/davecheney/status/604837853344989184?lang=en

ここにあなたの質問のコードスニペットの答えがあります

package main

import (
    "bufio"
    "fmt"
    "os"
)

/*
 Three ways of taking input
   1. fmt.Scanln(&input)
   2. reader.ReadString()
   3. scanner.Scan()

   Here we recommend using bufio.NewScanner
*/

func main() {
    // To create dynamic array
    arr := make([]string, 0)
    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("Enter Text: ")
        // Scans a line from Stdin(Console)
        scanner.Scan()
        // Holds the string that scanned
        text := scanner.Text()
        if len(text) != 0 {
            fmt.Println(text)
            arr = append(arr, text)
        } else {
            break
        }

    }
    // Use collected inputs
    fmt.Println(arr)
}

プログラムで入力を収集したくない場合は、これらの行を追加するだけです

   scanner := bufio.NewScanner(os.Stdin)
   scanner.Scan()
   text := scanner.Text()
   fmt.Println(text)

上記のプログラムの出力は次のようになります。

Enter Text: Bob
Bob
Enter Text: Alice
Alice
Enter Text:
[Bob Alice]

上記のプログラムはユーザー入力を収集し、配列に保存します。特殊文字でその流れを壊すこともできます。スキャナーは、カスタム関数などを使用した分割、さまざまなタイプのI / Oストリーム(Stdin、String)のスキャンなどの高度な使用法のためのAPIを提供します。


これは受け入れられる答えになるはずです。より正確な回答であるだけでなく、品質も向上します。
ダニエルファレル

11

スペースを含む入力を処理できるループ内で複数の入力を読み取る別の方法:

package main
import (
    "fmt"
    "bufio"
    "os"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    var text string
    for text != "q" {  // break the loop if text == "q"
        fmt.Print("Enter your text: ")
        scanner.Scan()
        text = scanner.Text()
        if text != "q" {
            fmt.Println("Your text was: ", text)
        }
    }
}

出力:

Enter your text: Hello world!
Your text was:  Hello world!
Enter your text: Go is awesome!
Your text was:  Go is awesome!
Enter your text: q

2
内部の「q」チェックでブレークを使用して、すべてを無限ループでラップすることもできます。ちなみに大答え!
テバネップ2016年

2
forループの条件を取り除くこともできるようになりました。
irbanana

6

パーティーに遅れました。しかし、1つのライナーはどうですか:

data, err := ioutil.ReadAll(os.Stdin)

コマンドラインで入力を入力したら、Ctrl + D(EOT)を押します。


os.Stdin「終了」しないので、すべてを読むことは不可能です。しばらくお待ちください...
gypsydave5 '16 / 08/18

2
Ctrl + D、つまりEOTを押します。
Shivendra Mishra

3
はい、それでうまくいきます-でメールを書くことを思い出させますmail
gypsydave5

5

このコードを試してください:-

var input string
func main() {
      fmt.Print("Enter Your Name=")
      fmt.Scanf("%s",&input)
      fmt.Println("Hello "+input)
      }

3
以下のように思えるScanf()の文字列に空白を受け入れていない
Eslam

4

次のように行うこともできます:-

package main
import "fmt"     

func main(){
    var myname string
fmt.Scanf("%s", &myname)           
fmt.Println("Hello", myname)       
}

3

いくつかのプロンプトされた値をきれいに読んでください:

// Create a single reader which can be called multiple times
reader := bufio.NewReader(os.Stdin)
// Prompt and read
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Print("Enter More text: ")
text2, _ := reader.ReadString('\n')
// Trim whitespace and print
fmt.Printf("Text1: \"%s\", Text2: \"%s\"\n",
    strings.TrimSpace(text), strings.TrimSpace(text2))

ここに実行があります:

Enter text: Jim
Enter More text: Susie
Text1: "Jim", Text2: "Susie"

2
また、strings.TrimSpaceは '\ n'を削除するので、良い方法です。そして、reader.ReadString( '\ n')もクロスプラットフォームだと思います。
user2707671

私はほとんどの場合、デフォルトで削除したいのだと思いますが、それが@Naren Yellavulaの回答としてのbufio.NewScannerの方が良い理由です
John Balvin Arias


0

私の場合、watcherコマンドを使用してプログラムを自動実行していたため、プログラムは待機していませんでした。プログラムを手動で実行するgo run main.goと、「テキストの入力」が行われ、最終的にコンソールに出力されました。

fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)

2
Scan*ファミリーの制限は、空白(例えばスペース)の区切り文字まで読み取ることです。
George Tseres
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.