【问题标题】:Golang: How do I use fmt.Fscanf() & fmt.Sscanf() correctly?Golang:如何正确使用 fmt.Fscanf() 和 fmt.Sscanf()?
【发布时间】:2022-01-07 04:58:15
【问题描述】:

我正在开发一个应该读取文件内容并从中提取数据的程序。我尝试使用 fmt.Fscanf() 逐行扫描内容,但由于某种原因,我无法使其正常工作。整行仅被扫描到第一个字符串参数中。我在这里做错了什么?

我假设它不起作用,因为值没有用空格分隔,但我找不到解决方案。感谢您的帮助和专业知识!

20220105|AA|1051302|4323|3132468|B,Q,N
20220105|AAA|61|0|62|Q
20220105|AAAU|19404|0|57137|Q,N
20220105|AAC|35524|0|39861|Q,N
20220105|AAC/WS|1180|0|2000|N
20220105|AACG|1805439|32577|3484265|B,Q,N
func main() {
  file, err := os.Open("./CNMSshvol20220105.txt")
  if err != nil{
    log.Fatal(err)
  }
  defer file.Close()

  var m map[string][]int
  m = make(map[string][]int)

  for{
    row := ""
    date := ""
    symbol := ""
    shortVolume := 0
    shortExemptVolume := 0
    totalVolume := 0
    markets := ""

    //Date|Symbol|ShortVolume|ShortExemptVolume|TotalVolume|Market
    var n int
    n, err := fmt.Fscanf(file, "%s\n", &row)
    fmt.Sscanf(row, "%s|%s|%d|%d|%d|%s", &date, &symbol, &shortVolume, &shortExemptVolume, &totalVolume,&markets)
    fmt.Println(date)
    if n == 0 || err != nil{
      log.Fatalf("Fscanf: %v\n", err)
      break
    }
    fmt.Println(symbol, shortVolume, shortExemptVolume, totalVolume)
    m[strings.ToLower(symbol)] = append(m[strings.ToLower(symbol)],shortVolume)
    m[strings.ToLower(symbol)] = append(m[strings.ToLower(symbol)],shortExemptVolume)
    m[strings.ToLower(symbol)] = append(m[strings.ToLower(symbol)],totalVolume)

  }

  //Retrieve values if the key exists
  for{
    fmt.Println("\n\n\n\nEnter ticker to retrieve short volume information.")
    var s string
    fmt.Scanf("%s",&s)
    data, ok := m[strings.ToLower(s)]
    if !ok{
      fmt.Println("Not Found.")
      continue
    }
    for _, value := range data{
      fmt.Println(value)
    }
  }


}```

【问题讨论】:

  • 使用 encoding/csv 和 |作为字段分隔符。
  • @Volker 不知道 encoding/csv 可以做到这一点。每天学习新东西。

标签: go gofmt


【解决方案1】:

fmt.Sscanf documentation 说:Sscanf 扫描参数字符串,将连续的空格分隔值存储到由格式确定的连续参数中

| 字符不是空格,每个格式占位符都独立于任何其他,所以%s| 并不意味着匹配任何字符串直到第一个|,而是匹配任何不包括空格的字符串,然后是@ 987654328@.

您可以逐行处理文件,例如使用strings.Split() by | 分割每一行,然后根据需要将值解析为变量:

row := "20220105|AACG|1805439|32577|3484265|B,Q,N"
tokens := strings.Split(row, "|")
if len(tokens) != 6 {
    log.Fatal("Bad line in file...")
}

// Do appropriate conversions...
date, err := strconv.Atoi(tokens[0])
if err != nil {
    log.Fatal("first token is not an integer")
}
symbol := tokens[1]
// ...

fmt.Println(date, symbol)

或者正如沃尔克在他的评论中指出的那样,您可以使用包encoding/csv并将其ReaderComma(分隔符)选项设置为|

f := `20220105|AA|1051302|4323|3132468|B,Q,N
20220105|AAA|61|0|62|Q`

r := csv.NewReader(strings.NewReader(f))
r.Comma = '|'
data, err := r.ReadAll()
if err != nil {
    log.Fatal(err)
}

// Process data, do appropriate conversions

fmt.Print(data)

【讨论】:

  • 谢谢! Strings.Split() 正是我想要的。
猜你喜欢
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-23
  • 1970-01-01
  • 1970-01-01
  • 2019-04-30
  • 2019-01-31
  • 1970-01-01
相关资源
最近更新 更多