douqianrou9079 2019-07-21 20:11
浏览 78
已采纳

为什么在使用fmt.Fscanf时出现“输入格式不匹配”​​的提示?

I'm trying to use fmt.Fscanf but I'm having hard time figuring out how. Having the following code:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var host, user, date, httpStr string
    var code, size int

    r := strings.NewReader(`127.0.0.1 - james [09/May/2018:16:00:39 +0000] "GET /report HTTP/1.0" 200 123`)

    _, err := fmt.Fscanf(r, `%s - %s [%s], "%s" %d %d`,
        &host, &user, &date, &httpStr, &code, &size)
    if err != nil {
        fmt.Printf("Failed to parse log line, error: %+v
", err)
        panic(err)
    }

    fmt.Println(host, user, date, httpStr, code, size)

}

Go playground: https://play.golang.org/p/zGxc6MXOF3a

I get:

Failed to parse log line, error: input does not match format
panic: input does not match format

goroutine 1 [running]:
main.main()
        .../fscanf/main.go:19 +0x57b
exit status 2

Why?

  • 写回答

1条回答 默认 最新

  • dourong6054 2019-07-21 21:51
    关注

    The error comes from how Fscanf parses space-separated strings. This becomes an issue when reading the date and HTTP string:

    When it reads the date, instead of reading 09/May/2018:16:00:39 +0000 it will read until the first space: 09/May/2018:16:00:39 then expect ].

    To fix this, it would make sense to parse the string as [%s %s], but this would fail more subtly. It would parse the timezone as +0000] because it stops at the first space, not according to the format string. The same issue occurs with the HTTP string: it stops parsing after the verb GET, then after the route /report, but when reading the protocol it reads HTTP/1.0" not HTTP/1.0.

    A working solution is as follows:

    package main
    
    import (
        "fmt"
        "log"
        "strings"
    )
    
    func main() {
        var host, user, date, tzOffset, verb, route, proto string
        var code, size int
    
        r := strings.NewReader(`127.0.0.1 - james [09/May/2018:16:00:39 +0000] "GET /report HTTP/1.0" 200 123`)
    
        _, err := fmt.Fscanf(r, `%s - %s %s %s %s %s %s %d %d`,
            &host, &user, &date, &tzOffset, &verb, &route, &proto, &code,
            &size)
    
        if err != nil {
            log.Fatal(err)
        }
    
        date = date[1:] + " " + tzOffset[:len(tzOffset)-1]
        httpString := verb[1:] + " " + route + " " + proto[:len(proto)-1]
    
        fmt.Println(host, user, date, httpString, code, size)
    }
    

    Here we ignore the brackets and quotes around the date and HTTP string when parsing, then remove them afterwards.

    Output:

    127.0.0.1 james 09/May/2018:16:00:39 +0000 GET /report HTTP/1.0 200 123
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥15 可见光定位matlab仿真