【问题标题】:Read lines from stdin until certain character从标准输入读取行直到某个字符
【发布时间】:2013-01-07 22:37:41
【问题描述】:

我正在学习围棋。

我的程序应该从标准输入读取数据,直到我输入带有单个句点的行。

package main

import (

  "os"
  "fmt"
  "bufio"

)

func main(){

  in    := bufio.NewReader(os.Stdin)
  input := ""

  for input != "." {
    input, err := in.ReadString('\n')
    if err != nil {
      panic(err)
    }
  }
}

我应该如何修改我的 for 循环,以在我输入一个点时停止程序?

我试图用 for 语句实现一个 while 循环,我的方法有问题吗,是条件错误,还是 ReadString 弄乱了我的数据?

【问题讨论】:

    标签: go


    【解决方案1】:

    以防万一其他人遇到这个问题:

    从 Go 1.1 开始,有一种更好的方法可以循环某些可用输入的行。这就是我今天要解决 OP 问题的方法:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func main() {
        scanner := bufio.NewScanner(os.Stdin)
        for scanner.Scan() {
            line := scanner.Text()
            if line == "." {
                break
            }
            fmt.Println(line) // or do something else with line
        }
    }
    

    scanner.Text() 自动去除尾随的换行符。

    【讨论】:

    • 对于它的价值,它不是 Text() 从令牌中去除尾随换行符,这发生在 Scan() 期间。与我相关,因为我想使用扫描仪上的 Bytes() 函数将令牌检索为字节。这也不包含尾随的换行符。
    【解决方案2】:

    ...ReadString 是否在弄乱我的数据?

    不,不是。它正在阅读到下一个'\n'。这意味着上面只有一个点的行将包含数据".\n"".\r\n",具体取决于操作系统。

    要删除行尾,我会做input = strings.TrimRight(input, "\r\n")

    【讨论】:

      【解决方案3】:

      使用任何 bufio 辅助函数的主要问题是它可能会读取超出停止字符'\n' 的更多数据。它读取缓冲区大小的所有可用输入。在并发访问 os.Stdin 的情况下,下一个读取器可能会错过一些之前由 bufio 读取的输入。下面是我的非缓冲“草稿”代码,用于绘制从输入流中读取直到 CR ('\n') char 的所有字符的并发安全方法。

      package main
      
      import "os"
      
      // echo a line in input to output
      // you may add exit signal in copy loop as well
      func main() {
          const BUF_SIZE = 128
          in := os.Stdin
          out := os.Stdout
          bufOut := make([]byte, BUF_SIZE)
          n := 0
          for {    // copy loop 
              // non buffered byte-by-byte
              if _, err := in.Read(bufOut[n : n+1]); err != nil {
                  break
              }
              if bufOut[n] == 0xa || n == BUF_SIZE { // reached CR or size limit 
                  if _, err = out.Write(bufOut[0 : n+1]); err != nil {
                      break
                  }
                  n = 0
              } else {
                  n++
              }
          }
      }
      

      【讨论】:

      • 只需在程序的早期将os.Stdin 的任何使用替换为缓冲的io.Reader 设置,并在任何地方使用该阅读器。
      • Dave C, (1) 我不知道为什么os.Stdin 需要离开。我从输入流开始,因为它涉及主题:“从 stdin 读取行直到某个字符”。 (2) 如果你有几个 goroutines 竞争相同的输入流,任何缓冲的 io 都会给你带来麻烦。
      • 关于第 (2) 点。我确实理解,在 GO 中并发访问标准输入中的行的惯用方法是让 bufio 阅读器从标准输入中读取并将行放入通道中。然后让 goroutine 竞争通道。在我的情况下,我必须使用外部流,因此非 bufio 代码对有同样问题的人很有用。
      【解决方案4】:

      刚刚注意到主题内的问题与标题中的不同。 有问题的初始样本的错误在于循环内的输入变量被重新声明。这就是为什么您的条件检查永远不会到达退出点的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-10
        • 2018-04-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多