终端Go应用程序中的多行输入

时间:2015-06-14 04:40:54

标签: go

我需要让用户输入多行文字到控制台。

这是我的代码:

package main

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

func main() {
    for {
        fmt.Println("How to read all lines here?")
        in := bufio.NewReader(os.Stdin)
        result, err := in.ReadString('\n')
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println("\nresult")
        fmt.Println(result)     

    }
}

我粘贴在控制台中:

    Hello
    World

输出:

How to read all lines here?

        Hello
        World


result


How to read all lines here?

result
        Hello

How to read all lines here?

result
        World

How to read all lines here?

result


How to read all lines here?

但我希望它是:

         How to read all lines here?

                Hello
                World


        result


        How to read all lines here?

        result
                Hello
                World

        How to read all lines here?

我想我需要使用类似EOF而不是'\n'的内容  但是怎么做呢?

更新

peterSo的回答是有效的,除非我试图从剪贴板粘贴一个中间有一个或多个空行的文本,例如:

Hello

World

打印

Enter Lines:
Hello

WorldResult:
Hello

Enter Lines:

更新2

伟大的更新后的peterSO答案现在甚至适用于空行的文字。

3 个答案:

答案 0 :(得分:5)

缓冲一组线并检测一组线的结束。例如,

package main

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

func main() {
    scn := bufio.NewScanner(os.Stdin)
    for {
        fmt.Println("Enter Lines:")
        var lines []string
        for scn.Scan() {
            line := scn.Text()
            if len(line) == 1 {
                // Group Separator (GS ^]): ctrl-]
                if line[0] == '\x1D' {
                    break
                }
            }
            lines = append(lines, line)
        }

        if len(lines) > 0 {
            fmt.Println()
            fmt.Println("Result:")
            for _, line := range lines {
                fmt.Println(line)
            }
            fmt.Println()
        }

        if err := scn.Err(); err != nil {
            fmt.Fprintln(os.Stderr, err)
            break
        }
        if len(lines) == 0 {
            break
        }
    }
}

控制台:

Enter Lines:
Hello
World
^]

Result:
Hello
World

Enter Lines:
Farewell

World

^]

Result:
Farewell

World


Enter Lines:
^]

要终止一组行,请在空行中输入:< ctrl+]>< Enter>。要终止输入,请输入一行:< ctrl+]>< Enter>。

答案 1 :(得分:0)

查看bufio.ReadString的文档,它指出传递给它的字符将导致函数停止读取和返回。如果您想接受多行输入,您需要提出一些方案来区分继续语句的新行(' \ n')以及终止声明。

编辑:这是一个糟糕的快速hacky示例,它扩展了代码以识别多行输入。它通过定义"终止"来实现这一点。语句是仅包含" \ n"的空字符串。您可以看到它只是将多个读取缓冲到一个"块"中。您可以更聪明地直接阅读键盘,但无论您是否必须定义一些可以编程识别为多行与单行的方案。

package main

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

func main() {
    cnt := false
    var txt []byte
    for {
        result := make([]byte, 1024)
        if cnt == false {
            fmt.Println("How to read all lines here?")
        }
        in := bufio.NewReader(os.Stdin)
        _, err := in.Read(result)

        if err != nil {
            fmt.Println(err)
        }
        if result[0] == '\n' {
            cnt = false
            fmt.Printf("<----\n%s---->\n", string(txt))
            txt = txt[:0]
        } else {
            txt = append(txt, result...)
            cnt = true
        }
    }
}

答案 2 :(得分:0)

EOF无法帮助您,因为io.EOF的类型为“error”,但in.ReadString需要一个字节(序列'\n' - 是字节)。但无论如何,如果我了解你的目标,你需要一些方法来停止从stdin读取。例如,一个特定的字符串。像mysql客户端期望“退出; ”字符串来结束您的会话。

看看扫描线示例 http://golang.org/pkg/bufio/#example_Scanner_lines 并改进它取代

fmt.Println(scanner.Text()) // Println will add back the final '\n'

有类似的东西:

allInput += scanner.Text() + "\n"
if scanner.Text() == "exit;" {
    //your actions on exit...
    //...    
    fmt.Println("Exiting. By")
    return
}

或者,如果您希望编程在管道中工作并从其他程序输出中获取多行输入,则可以使用io.ReadFullPipeReader函数